Showing posts with label assembly. Show all posts
Showing posts with label assembly. Show all posts

Sunday, November 12, 2017

DLL Hijacking - DLL Man-In-The-Middle

Hello, guys!

I hope that everybody is doing fine! :)

I was working in this PoC on my free time and now I could get enough time to bring the technical of it. It take a while because I first wanted to bring some introductory posts before writing the technical stuff. So let's do it!

First of all I hope that you had read my last posts to a better understanding of what I will show here, because I will not explain in details everything. So the prerequisites for this post is:
What I utilized to do this ?

Github Project

Overview


I have been studying more in-depth the PEB hooking (this post is not about PEB hooking) to learn more thoroughly how Windows Internals works. My way to learn is coding, practicing. I like to brush bits :). Basically the PEB hooking stole a module from some process, changing addresses in the LdrModules located in the PEB. But for this I needed a DLL that exports the same functions that the original do.

To export all functions from a DLL I coded the "DLL Exporter" tool to extract the functions exported by some DLL. It access the export directory and generate 2 files for NASM. I included the code generated in the main code of the fake image DLL ASM. Of course for this example it doesn't matter, because I only exported 1 function, anyway it worth to take a look on it to see how it works.

In this example I coded a program that simulate a message exchange, there is no socket connecting to keep it simple. But you got point right ? The program passes the message to a DLL that encodes it and hypothetically would send encoded message to somewhere. 

To do this PoC I made a fake DLL that exports the same function of the original. This fake DLL grabs the message, log it in a file before encoding it and send the execution to the original one, without injecting any code neither in the executable nor original DLL, just rewrites the IAT of fake DLL. I just named the fake image file as the same name of the original image, so when the Windows Loader searches for the DLL it will load the fake one.

Problems


Theoretically I just have to leave the windows load the fake DLL and inside of the fake image I load the original DLL, then I can call all functions that belongs to it. I could do this just with LoadLibrary and GetProcAddress, right ? But imagine a DLL with a LOT of functions, the work I would to do to make everything callable would be huge and painful.

So what I did was to link the original DLL to my fake DLL and there is where I found the problem. When the program loads the fake DLL consequently the original DLL is loaded, since the fake image has the same name as the original image, windows loader will end up linking fake image to itself and a Deadlock is set. So when the fake image is called by the process it can't jump to the original image and keeps calling itself forever. To set everything in the right place I had to alter the IAT (Import Address Table) of the fake DLL.


Solution


As a solution to this problem I had to rewrite the IAT with the original function addresses and I did it with NASM. At this point if you don't know what is a IAT, please read my previous topics and all the references I gave there. The solution is to load the original DLL image, save the AddressOfFunctions (Export Directory), save the IAT (FirstThunk - Import Directory), change the IAT memory protection (protection against writing), then I just iterated through the AddressOfFunction rewriting the addresses to the IAT by the addresses of AddressOfFunctions. Now all my imported functions in the fake image DLL will call the original image DLL functions.

Spliting the Project


I will give a brief explanation about the source code. I left comments in the source to help in the reading, but the code itself is self explanatory. Anyway any doubt or question just contact me. In the next posts I will bring CMake files to make easy to compile, for now I just make some PowerShell scripts to do it in each folder.
  • Folders
    • dll
      • This folder have the code of the dllsend.dll.
    • dll-consume
      • This folder contains the code of the program to consume the dllsend.dll.
    • dll-exporter
      • This folder contains the program that receives a DLL in the command and generate two files. dll_parameter.dll.ext and dll_parameter.dll.subs.
        • dll_parameter.dll.ext contains the "extern" code of all exported functions to append in the ASM code.
        • dll_parameter.dll.subs contains the function declaration to append in the ASM code.
    • dll-fake-asm
      • This folder contains the body of the fake DLL image. I coded all the process using NASM and GoLink to link the compiled object with the original DLL image.
      • make.ps1 has the logic to link the fake DLL image. 
      • In the GoLink you have to inform all the exported functions. In this case you can adapt the DLL Exporter to generate this part easily.

Walking through the process


I will assume that you have compiled everything and I will just walk to the main parts of the process. The dll-consume is very straight forward, you type your message, then it back to you with the encoded string and the it's hex dump.

dll-consume compiled

So as I mentioned before I just renamed the original DLL adding a "2" in the end. So let's see what happen inside of this process. You will see that since the fake DLL is pure ASM code it's size is tinier than the original image DLL compiled with GCC. 

List of files

So I already mentioned before how to find the OEP (Original Entry Point) of the programs compiled in GCC. You can find the pattern that GCC uses to do this or you can go directly in the inter-modular calls made by this module m.exe. This is the main function:

Main function of m.exe

As I always said, take a moment to walk-through the program, it's important to train your eyes with assembly code. In the image above you will see the IAT of the m.exe module in the line that calls the send function where you see a jump to imported function. At this point in debugging you can see all the modules loaded in the memory tab. Since original DLL was loaded in the entry function of my fake image DLL it is already loaded in the memory tab.

Memory mapping

The main/entry code of the fake image DLL already was executed when the Windows Loader loaded the fake image. To step through this part in the debugger you can check Dll Entry option in the preferences.

Dll Entry - Debugging

I already set a breakpoint in the send call, then I stepped into until I get the fake send function.

As you can see it's pretty straight forward. I imported some C functions to save the message in the file log.bin. Opened a handle to the file, wrote to it and closed the handle. After the log process, I restored the register context and jumped to the original send function.

I could enhanced this fake send function more to make the log better, but it useless. To practice ASM, try to enhance it inside the fake DLL code. Make a breakline in each message and save it to the log.bin, if you analyze the code you will see that is easy.

Fake function 'send' disassembled

I will not step-by-step through the IAT rewriting, I leave to you to debug it. Open the DLL on CFF Explorer and debug the entry function of fake DLL. The code itself has a lot of comments. Any help that you may need just contact me, I would be glad to help. ☺

Countermeasures ?


There are some countermeasure against it, you just have to be creative about it. For this you could check the MD5 of the DLL before call it or you could count how many modules are loaded in the process memory space. As you saw in the walk-through there is a exceeding module dllsend2.dll and with this information you can define if your application has been compromised or not.

Anyway it's hard to fight against these things. In RE world, programmers have to do all they can to make the work of reversers as hard as possible in order to avoid the RE itself.

Conclusion


In computer world everything is possible it's just a time to understand how to do it. I did this PoC for learning purposes and a better understand the Windows Internals. I hope that with this technical example you can learn a little with it too. Thanks for reading.

I didn't walked through the loading process of fake image DLL because I think my comments in the code are pretty self explanatory. Anyway any questions feel free to contact me. 

Friday, September 1, 2017

Solving the first exercise

Hello, there!

In this post we will reverse engineering the exercise-program that I left in my previous post about compiling C programs.  I tried to make well explained and objective. So any question let me know.

Prerequisites:
In the end of the post linked above there is a code that we are going to use in this post. Compile it and let's begin. Tools in this post:
In my last post I left an exercise (simple one) that the goal was to reach the "Secret Stuff!". In this post I will show two ways to do it. It's very simple program coded in C. I assume that already have compiled the program as the link in the prerequisite.

First I ran it to see what happens:

Fig1 - Running the program

Nothing much, just a simple "Not Valid". Well I will run the strings.exe from SysInternals to see if we can find something interesting. I configured my strings program in the Path environment variable to be easy to execute. Take some time and look closely to anything that could be interesting. There are a lot of strings here, but the 90% is standard, besides this doesn't seem encrypted. Taking a time rolling up and down, I could find some interesting strings:

Fig2 - Strings the program

Well I see that I will have to type some password, but when I first ran it nothing was asked to me. Why this ?. And we have the secret stuff too, so we just began with it since our goal is to reach that part, we deal with password in the way to it if we had too.

We could open in some software like CFF Explorer to dig into the imports and so on, but doesn't seem necessary at this point. So let's open it in the IDA Pro and see if we can find anything interesting. With the program opened in the IDA Pro let's seek for our goal in the tab Strings, click in the tab and search for the "You reach the secret stuff!!", then double click in the line with the string. IDA sent us to the part of the section rdata in the offset that starts the string. We have to click in the offset name aYouReachTheSec and press the X key, then we can choose the references for this offset, since we just have one let's double click it. We were drove to a function that uses this string sub_401517, we can click on it's name and press N to rename it, I renamed to SecretSub. Ok, this would be enough to crack it. I will show two manners to do it, cracking it(Patching) and bypassing it. To bypass we just have to find how to reach the secret stuff without hardcode/patch the binary.


Fig3 - String offset in the section rdata


Bypassing the binary


To bypass the binary first we have to find how the binary reach this SecretSub in normal way, so click in the name of the sub and press X to find the references to this sub. We only find one reference:

Fig4 - Main flow

As we can see we have a little piece of the program that asks for some password using the scanf (C API) to get the password, call sub_401460 and right after uses a cmp eax, 1. We can deduce that we get the password and then sub_401460 will check for the password to see if it is right and return to eax if the password is right or not. Let's see how the binary validates the password double clicking in the sub_401460. We were drove into the sub and I already rename the sub to PasswordCheck making it easy to identify.

Fig5 - Password checking

We can see some loops, some ifs and in the end of the sub we have only one piece of code that will drive us to the good end (mov eax, 1), the other pieces just print "Not Valid" in the screen. The first part is interesting, many hex values stock in variables at the first piece of code, we will look at it after. IDA name the variables for us to make our work more easy, this variables are just offsets in the stack for example [ebp+var_c] without the IDA would be [ebp-C], so IDA put variable names in the offset to make our lives easier, we can even rename the variables clinking in their names and pressing N to make it more easy to read the code.

After looking a little at this code we are able to identify that the first part seems like a counter adding in the variable var_10 to be compared in cmp [ebp+var_10],14h , the size in this variable has to be lower than 14h (decimal 20) if it was larger then we got a "Not valid" message.

We can deduce to this point that the password must be under 20 characters. In the next block it uses the variables var_c (counter) and var_1B (string reference), the var_c is an index reference to the string array for both the argument arg_0 (types password) and the var_1B (hardcoded password). It compares byte per byte from both variables to check if the password matches. So we can take the var_1B till var_11 to get the expected password. If we get the whole and put it together we can convert hexadecimal to unicode characters, but we have to keep in mind that since the value is in the stack it is disposed in little-endian order, thus to convert it we must write them in the reverse order like 3332312D3132332D323331 converting this we get "321-123-231". Now we have the password, but if we run it we can't get in the part to type the password, so we have to dig a little more. Let's back a little and see what it have to does to reach the part that asks for the password.

As we can see in the Fig4 there is a cmp with the arg_0 in the main function and right after a conditional jump JG, since this program was written in C we know that in the main function the first argument by default is the amount of arguments passed to the program to execute. If you ran the program in the CMD the first argument will be always the complete path to the program that is been executed. Therefore we must have more than one argument when execute this program, to do this we just add any text after the program name like ">main.exe newargument" if you execute like this we can bypass this part and reach the password part. Let's try it:

Fig6 - Program bypassed

Voilá! We did it, we bypassed the exercise without patch anything.

Patching the binary


Now let's do a quick and functional patch to get this working without type anything. We want to reach the secret stuff without efforts, execute the program and reach it. How can we do it, now we know the address that calls the SecretSub, we just have to alter that conditional jump JG that was made right after the comparative in the program's argument and JMP directly to the call to the SecretSub. We can do this using the x64dbg. Open the program in the debugger reach the address using the CTRL+G in the address 40153E and press space bar to patch this line. To work properly we can't simple call or jump inside the secret stuff because the program must return to properly exits the execution, then we simply jump directly to the right call using a unconditional jump jmp 0x40158E. Press CTRL+P to open the patches click to patch file and choose a name to the new executable and save it. Now try to run it.

Fig7 - Patched program

Voilá! Now we access the secret stuff without have to type anything.

Well that is it folks! This program was quite simple with no anti-technique at all. In the next posts I will try to bring more difficult exercises. :) Thank you for you time and see you soon! Any questions at all please let me know! :)

Thanks! Best regards!

Monday, July 10, 2017

Basicando o Assembly

Introdução ao Assembly

Fala galera, eu aqui de novo trazendo mais tópicos básicos de engenharia reversa, básicos por enquanto, viu ?! Quero trazer algo mais desafiador nos posts futuros, porém deve haver uma introdução primeiro. Desculpem qualquer bobeira que eu disser durante o post e se eu fizer algo por favor fiquem à vontade para me comunicar. Engenharia reversa só pode ser feita com conhecimento em Assembly, não tem outro jeito, ou aprendemos ou aprendemos.

Caso você não tenha lido o meu último post, eu recomendo. Eu tento abordar de uma forma mais dinâmica a computação. Então tudo no fim é assembly como você já deve saber, não importa que linguagem você utiliza ela vira assembly no fim ou no mínimo é interpretada através dela. De qualquer modo é bom saber assembly, fora que não é tão difícil entender assembly ainda mais se você já usou alguma linguagem funcional, como pascal por exemplo.

Assembly não é universal, diferentes assemblers compilam para assembly de diferentes formas e com base na arquitetura utilizada. Afinal alguns processadores interpretam as instruções de forma diferente, assim como é nas linguagens de alto nível. O que muda é a sintaxe, os conceitos permanecem.  Nas minhas postagens trarei a arquitetura IA-32 (que é mais comum pelo mundo afora). Lembrando que esse post não é uma aula completa, mas abordarei os conceitos para que possamos iniciar posts mais técnicos.

Como vimos no meu post passado, o computador trabalha com o conceito de Memória-Dados X Instruções. Ele armazena tudo na memória e depois interpreta os dados e instruções de acordo com a necessidade e a forma como comandamos ele. Se você passa determinado para a CPU dizendo que é pra ela executar, ela vai tentar executar. Mais pra frente veremos como isso acontece.

 
Computador / Memória, CPU, Dispositivos IO(Entrada-Saida) e BUS

O processador possui alguns ponteiros que são utilizados para ajudar a CPU durante toda a sua execução, uns apontam para as instruções e outros para os dados. Basicamente é o que eu já havia dito, faça determinada operação com os determinados dados. Então temos o ponteiro de instrução instruction pointer e o ponteiro de dados data pointer. Nós trabalharemos muito com eles nos posts futuros. O ponteiro de instrução como o nome diz, aponta para a memória que contém as instruções e o ponteiro de dados aponta para a memória que contém os dados, e com essas informações a CPU faz os procedimentos necessários.

 
Unidades da CPU X Memória

Não se assustem explicarei em mais detalhes. A CPU guarda os valores desses ponteiros em registradores (registers). Conforme o processador executa as instruções o ponteiro de instrução (instruction pointer) aponta para a próxima instrução, assim como o ponteiro de dados. Uma instrução possui entre 1 e 3 bytes e é chamada de opcode (operation code(código de operação)). Então basicamente o assembly possui 3 partes principais, opcodes (operações), data sections(seções de dados) e directives.

Opcode


Código mnemônico, é uma representação mais compreensível dos opcodes. É uma forma mais tranquila para se ler do que o código de máquina. No exemplo abaixo temos do lado esquerdo o código de máquina e do lado direito os mnemônicos. Temos por exemplo o opcode/instrução '89' que é o a instrução MOV. Diferentes "tipos" de assembly representam esses valores de formas diferentes.

 
OllyDbg / Direito Assembly, Esquerdo OpCodes

Data


As data sections são espaços utilizados para armazenar os dados que as instruções precisam buscar para executar. Então os dados podem estar em alguma seção da memória ou ele pode usar a stack (mais depois). Todos os dados são armazenados utilizando sua representação em hexadecimal, e são referenciados para serem utilizados por seus endereços em memória. Tudo que é armazenado na memória possui um endereço. Veremos que os dados ou endereços podem ser requisitados através de uma immediate constant que está explícito diretamente na linha de execução ou pode estar em alguma parte da memória, isso inclui o stack frame.


Directives


Directives são elementos utilizados em assembly para informar ao assembler (compilador do assembly) como esse determinado dado deve ser utilizado. Por exemplo se você precisa armazenar um número float o assembler precisa saber que tipo de dado é para armazená-lo de forma correta. Ou quando você quer utilizar um dado que está em um determinado endereço de memória, por exemplo. As directives criam seções na memória para armazenar os tipos de dados. Uma das directives mais importantes é a ".section" que cria seções em memória para os determinados tipos de dados.

Sections


Nós temos vários tipos de seções, podemos até criar outras se quisermos. Contudo as seções listadas abaixo são padrão:

  • .text:
    • Todos as instruções que o processador executará são armazenadas nessa seção. Dados não são permitidos aqui, a não ser os immediate constants que como eu disse antes são representados diretamente na linha de instrução. Como uma atribuição de valor a = 5, mas isso depende do programador assembly ou do compilador nas linguagens de alto-nível.
  • .data:
    • Esta seção é responsável por armazenar todos os dados que serão utilizados pela seção .text. Serão referenciados através de endereços de memória. Como program.ADDRESS, por exemplo.
  • .bss:
    • Esta seção é utilizada geralmente para dados não inicializados, que são armazenados durante a execução do programa. Acredito que o nome da seção mude de acordo com as linguagens.


Arquitetura IA-32


A arquitetura IA-32 foi desenvolvida para os processadores pentium pela Intel. Não tenho certeza se é realmente a mais utilizada atualmente, contudo é MUITO conhecida, possui bastante documentação e bem utilizada. Quando estamos aprendendo assembly a arquitetura é só a sintaxe de como escrever, para migrar para outras arquiteturas fica mais fácil depois que aprendemos uma bem, pois o conceito é sempre o mesmo o que muda é como escrever. Algumas arquiteturas possuem mais instruções ou instruções mais elaboradas e outras menos. A arquitetura IA-32 é dividida basicamente em 4 partes:

  • Control unit (Unidade de controle):
    • A unidade de controle é responsável por trazer da memória os dados e as instruções. Ela então traduz essas instruções em micro-operações e passa para unidade de execução. Após a execução o resultado retorna para a unidade de controle que armazena o resultado.
  • Execution unit (Unidade de execução):
    • Executa todas as micro-operações e retorna o resultado.
  • Registers (Registradores):
    • Os registradores são responsáveis por armazenar dados e endereços de memória. Esses registradores estão na memória interna do processador. O processador mantém os dados na memória interna para deixar a sua execução mais rápida, pois o processo de ir buscar na memória RAM do computador é muito mais lenta.
    • Para manter o post objetivo não escrevei extensamente sobre todos os registradores, contudo estou deixando as referências no final do post com um conteúdo mais acurado. Basicamente há 4 tipos de registradores (Tem mais, veja nas referências):
        • General Purposes (Propósitos gerais): 8 registradores de 32-bits. Como o próprio nome diz, são registradores gerais, podem armazenar dados e endereçõs de memória.
        • Segment (Segmentos): 6 registradores de 16-bits. Usados para acessos de memória.
        • Instruction Pointer (Ponteiro de instrução): 1 registrador de 32-bits. Aponta para a instrução que deve ser executada pelo processador.
        • Floating-point (Ponteiro de Float): 8 registradores de 80-bits. Para trabalhar com os números de ponto flutuantes.
  • Flags:
    • Flags são utilizadas para manter controle das operações executadas pelo processador. Através dela sabemos se as operações funcionaram ou não. Certas flags são marcadas de acordo com a operação executada. Veremos melhor sobre elas. 

Registers


General Purposes


Esse tipo de registradores são utilizados principalmente para trabalhar com os dados que as instruções/operações usam. Esses registradores possuem um tamanho de 32-bits, porém são subdivididos em 16-bits e 8-bits. 

  • EAX (32-bits):
    • AH (16-bits):
      • AL (8-bits)
  • EBX (32-bits):
    • BH (16-bits):
      • BL (8-bits)
  • ECX (32-bits):
    • CH (16-bits):
      • CL (8-bits)
  • EDX (32-bits):
    • DH (16-bits):
      • DL (8-bits)
  • EDI (32-bits):
    • DI (16-bits)
  • ESI (32-bits):
    • SI (16-bits)
  • EBP (32-bits):
    • BP (16-bits)
  • ESP (32-bits):
    • SP (16-bits)

OllyDbg / Registradores e Flags

Esses são registradores que trabalharemos na maior parte do tempo. É importante ressaltar que modificar um registrador da cadeia mais alta modifica também a cadeia mais baixa. Por exemplo se armazenarmos um valor em AL e então colocarmos outro valor em EAX o valor que havíamos colocado em AL foi modificado pelo novo valor colocado em EAX já que AL é EAX.

Alguns desses registradores são utilizados de forma padrão, como é o exemplo dos registradores EBP e ESP que são utilizados para controlar o stack frame. O stack frame é um bloco de memória utilizado para controlar o contexto de valores e dados de uma determinada function/method, por exemplo quando declaramos uma variável dentro de uma função, esse valor é armazenado na stack frame. Utilizamos a stack  também para passar valores via parâmetro na chamada de outras funções, utilizando a instrução push que armazena os valores na stack, veremos melhor na prática no decorrer dos posts.

Como eu sempre digo, é importante programar uma linguagem "baixo-nível" tipo C ou C++ que a curva de conversão para o assembly é menor, além do que você tem uma prática de manuseio diretamente com a memória. Com isso você tem uma visão melhor de como esse código fica em assembly. No decorrer das minhas postagens trarei bastante código C para analisarmos.

Segment


Antigamente podia-se escrever diretamente na memória física, pois o processador permitia esse tipo de ação, esse modo é chamado de real mode. Atualmente o real mode ainda funciona porém de forma limitada. O modo que é utilizado atualmente pelos sistemas operacionais (Windows NT em diante) é o protected mode com o conceito de paginação de memória, dessa forma fica explícito que em segmento de código não pode ser escrito nada, somente em segmento de dados. Pode-se também descrever blocos de memórias com determinados níveis de acesso. O assunto é extenso, vamos com calma ;p

Portanto os segmento de registros são utilizados para identificar onde os dados estão localizados em memória. Cada registro de segmento possui um ponteiro para a section (seção) onde ele irá pegar os dados necessários. Os segmentos são:

  • CS: Segmento de Código.
  • DS: Segmento de Dados
  • SS: Segmento da Stack
  • ES: Segmento Extra
  • FS: Segmento Extra
  • GS: Segmento Extra
Cada um deles é usado em casos específicos. Por exemplo, se você possui um endereço dentro do registrador EAX que é um endereço de memória dentro da seção de dados e você precisa guardar a informação que está em EBX, você verá algo como:

MOV dword ptr ds:[EAX], EBX

Com isso você está movendo a informação que EBX contém para dentro do endereço de memória que está localizado em EAX e dentro do segmento DS (segmento de dados), veja que você não está guardando dentro do registrador EAX, mas sim dentro do endereço que EAX aponta e na seção em que o segmento DS aponta.

 
OllyDbg / Immediate constant sendo movido para dentro da stack

Veremos muitos exemplos práticos. Que é o melhor meio de aprender!

Flags


As flags são mantidas em um único registrador chamado EFLAGS e cada flag é representada por um 1 bit dentro desse registrador. Como eu disse antes as flags são utilizadas para controlar o sucesso ou a falha das operações/instruções que o processador executa. Por exemplo os JUMPS (saltos) condicionais, eles usam algumas flags como referência para saber se o salto irá ser realizado ou não. Jump como o nome diz é um salto para algum endereço de memória, saltar para outro endereço de memória com outras instruções, ou seja continuar a execução a partir de outro endereço, outro ponto dentro do programa. Flags são divididas em 3 grupos:

  • Status Flags
  • Control Flags
  • System Flags

Vou falar basicamente sobre as status flags. Nas referências no fim do post tem bons livros com mais informações e de forma mais acurada, a ideia aqui é objetividade e macro-informação. As flags são um "sinal" ou status do resultado das operações matemáticas executadas pelo processador. As flags são :
  • CF: Carry Flag.
    • Carry flag é usado como suporte para as operações binárias salvando o carry ou o borrow. Utilizado para "carregar" o bit que sobra da operação. (Post introdutório de computação) Geralmente usado em operações unsigned.
  • PF: Parity Flag.
    • Quando a soma de 1s do valor resultante da operação é par.
  • AF: Adjust Flag.
    • Usada no Binary Coded Decimal (BCD) quando é um borrow ou carry. Como o próprio nome diz flag de ajuste do valor referente ao byte que representa a grandeza dentro do BCD. É um assunto complicadinho, indico leitura na referência (Richard Blum).
  • ZF: Zero Flag.
    • Usada quando o resultado de uma operação binária é 0.
  • SF: Sign Flag.
    • É usada em operações com números signed, é algo como números sinalizados (positivo ou negativo). Leia o post introdutório que tem um bom conteúdo lá. Esta flag é marcada quando a operação resulta em um número negativo.
  • OF: Overflow Flag.
    • Esta flag é utilizada em número signed quando a operação resulta em um número maior do que pode ser armazenada, ou seja deu erro. 

O assunto é complicadinho mesmo, mas com a prática a mais pesquisas chegaremos em um entendimento bacana. Qualquer dúvida estamos ai.

Stack


Stack é muito importante se tratando de engenharia reversa ela é utilizada o tempo todo durante a execução de qualquer programa. É utilizada para guardar dados de curto-prazo por assim dizer. Como eu disse antes, quando a execução entra dentro de uma função é criado uma nova stack frame  que seria um pedaço ou um bloco dentro da stack reservado para a função que está sendo executada. Stack geralmente é utilizada para:
  • Salvar os valores dos registradores:
    • Geralmente é utilizada para guardar valores de um registrador quando este mesmo registrador precisa ser utilizado em outra operação. Depois esse valor pode ser recuperado.
  • Alocação de variáveis locais:
    • Como já disse, suas variáveis locais ficam alocadas dentro da stack frame quando a execução entra em determinada função. E quando você precisa utilizar esses valores é usado o segmento que falamos antes, SS, stack segment.
  • Passar parâmetros para funções:
    • Para chamar determinada função geralmente é utilizado a instrução PUSH para enviar os valores para a stack e então chamar a função com a instrução CALL. Geralmente esses parâmetros são passados de forma reversa, da direta para a esquerda. f(p1, p2, p3) então passamos PUSH p3,p2,p1 e efetuamos a CALL.
  • Guarda o endereço de execução após a instrução CALL:
    • Quando o programa executa uma instrução CALL o curso de execução é alterado, então antes de uma CALL ser efetuada ela salva o endereço de execução que está na linha abaixo da CALL, pois quando a função termina de executar ela precisa retornar pro FLOW de executação na qual ela estava antes, isso acontece depois da instrução RETN ser executada.

Quando o programa entra em uma função as variáveis do escopo dessa função são armazenadas na stack. A stack nada mais é do que um pedaço de memória que o programa utiliza guardando os dados necessários. Para guardar os dados na stack utilizamos a instrução push e para resgatar os valores da stack utilizamos a intrução pop.

Toda vez que a execução do programa entra em uma função um stack frame é configurado. Stack frame nada mais é do que um bloco de dentro da stack. O stack frame é limitado pelos registradores ESP e EBP. ESP aponta para o topo da stack e o EBP para a base da stack. Vejamos um exemplo de código em assembly que realiza o stack frame:

PUSH EBP
MOV EBP,ESP
SUB ESP, SIZE

Primeiro o valor de EBP é salvo na própria stack para quando sairmos da execução da função o antigo stack frame possa ser restaurado. Então o valor que ESP está apontando agora é a nossa nova base do stack frame. Lembrando que o ESP é o topo da stack, então imagine que estamos colocando uma nova pasta de arquivos em cima de uma pasta de arquivos já existente. Quando a execução da função terminar imagina que retiramos essa pasta de arquivos que foi colocada em cima e sobra a pasta que já estava lá. Desta forma vemos que a stack funciona como LIFO (last in, first out) último que entra, é o primeiro que sai. Então por último é utilizado a instrução SUB que faz com que ESP aumente de tamanho, aumentando o tamanho do nosso stack frame.

Geralmente esse SUB é feito quando já se reserva o espaço da variável então somente é necessário acessar esse espaço dentro do stack frame diretamente usando nosso segmento de stack, SS, que vimos anteriormente. Teriamos algo parecido com isso:

mov EAX, PTR SS:[ESP+4]

Nessa última instrução o valor que está dentro de ESP somado com 4 bytes de posição, nos dá o endereço da variável desejada é movido para o registrador EAX. Nesse caso a variável é [ESP+4]. Se tivéssemos mais uma variável poderíamos ter outro endereço para ela como [ESP+8].

Uma das coisas que temos que entender é que a stack cresce para os endereços de memória menores, ou seja ela cresce para "baixo". Quando um programa começa sua execução a stack começa em seus maiores endereços e vai crescendo para os endereços menores. Vamos ao exemplo:

 
Funcionamento da stack

Heap


A Heap é uma área da memória onde os programas utilizam para alocação dinâmica de memória. O sistema operacional geralmente cuida dessa parte para os programas, então quando eles são iniciados e precisam de uma HEAP por alguma razão, o próprio sistema operacional cria este espaço em memória e entrega um ponteiro para esse espaço ao programa. Quando temos uma constante ou uma variável já iniciada como por exemplo:

char newText[] = "Testing how code storing data.";

O compilador já se encarrega de colocar o valor desta variável na seção de .data que é a seção onde ficam os dados inicializados do programa. Então dentro da execução do programa o compilador já coloca o endereço direto na linha da instrução que está sendo executada, pois o programa já sabe onde armazenou esta informação. Esse endereço podemos chamar de immediate constant dentro do programa ficaria algo como  program.ADDRESS, sendo ADDRESS o endereço da variável dentro da seção.

Contudo quando você vai carregar um arquivo externo o programa precisa alocar um espaço para esse arquivo e o tamanho que será necessário é dinâmico, então a HEAP será necessária. Se você abrir um arquivo de 5Kb então uma HEAP com o tamanho necessário será disponibilizada. Se você carregar um arquivo de 1Mb, então uma HEAP com o tamanho necessário será disponibilizada com o tamanho necessário. Heap nada mais é do que uma alocação dinâmica de memória.

Temos que ficar atentos quando se trata de HEAP em engenharia reversa, pois muitas informações importante são registradas nas HEAPs, veremos mais no decorrer dos posts e na prática como funciona.

Conclusão


Bom galera é isso! Quero pedir desculpa de antemão para qualquer erro ou mal-entendido durante a explicação. Estou tentando ser o mais objetivo e didático possível, contudo passar tudo isso em um post só é MUITO complicado, pois há muita informação. Acredito que com esse macro de informação irá facilitar e direcionar as pesquisas em cima do tema, pois sei que não da pra entender tudo só com esse post.

Qualquer dúvida em cima do tema é só me procurar, se eu puder ajudar ajudarei com maior prazer. E se eu não souber, pesquisaremos juntos. O intuito é só aprender. Quem sabe se juntar uma galera legal não montamos um grupo de estudo. Fica a dica. Qualquer coisa "tamo ai". :thumbs_up: 👍


Referências

  • Google
  • Eldad Eilam - Reversing: Secrets of Reverse Engineering
  • Reverse Engineering Code With IDA Pro
  • Professional Assembly Language - Richard Blum


Saturday, July 8, 2017

Writing and compiling a program in C

Hello there!

Today I want to bring a short post where I will show you how to write a program in C and compile it with GCC on Windows. This post will be useful, because we will need to compile the sources that I will bring on future technical posts. My goal is not to teach C programming, there is a lot of content about it on the web. Of course that I will help you along the posts with references about the code sources.

I recommend reading the previous topcis:



The GCC


Since I will not bring the executable here instead just the C code for you to compile on your own environment. In this way you can understand better how C code turns into Assembly code. Like a said in the previous topics, it's important to know programming in reverse engineering even if somebody tells you that isn't. There is no ultimate truth, so I'm open to any comment, tips or criticisms.

Well, let's do it! First we have to download the GCC, I'm using the MinGW to install it. There is a lot of C compilers out there, I pick the MinGW for convenience.




Download and install it at "C:\mingw" to be easy to access. Skip any checks to install components, just finish the installation. We will install the GCC via console on the next step. Once you have installed it, open the CMD or PowerShell goes to the mingw folder.


cd c:\mingw\bin
mingw-get.exe install mingw32-gcc-bin

We will only install the bin component, because we only want to compile our code. After the download process by the MinGW we are good to go, to write and compile our program.

To use the GCC directly, I mean through any folder in console you have to add the path of GCC to the Environment Path property.



GCC compiles our source with some initialization code that is default for every compilation, as I could see so far it starts to write the assembly from given address (0x401460), this is for the standard compilation setting. Let's see it in the next example. I wrote this simple code in C to test our GCC whether it's ok or not:


#include <stdio.h>

int main(){
   
    printf("Hello There. VerseInversing!\n");
   
    return 0;
}

Copy the code below on your favorite editor, save it like "sample.c" on C:/. Now open the console and run the command:


cd C:\
gcc sample.c -o sample

If everything it's ok you should see a sample.exe created on C:\. Just type it on console and execute it.


./sample.exe

Cool uh ? haha

Well, now we have to see how the assembly was generated. I was using the OllyDbg, but since the x64dbg has becoming very popular I'm giving it a try. It's a nice debug tool updated very often, have many features embed in it and many other good things. Download at:




Program loading (Very simple approach)


Before we get our hands dirty, let's see basically how the programming execution works. So first of all I assuming that you read the previous topics. So, to execute a program (binary file) the windows needs to load this file into memory so it takes the file and simply put it into the memory. Then each file type is interpreted in different ways when loaded into memory. The executable file have the header with key information that let the windows load it and execute it properly.

So the executable file always have the PE (Portable executable) header, without it the OS just can't load it. In the PE Header we have vital information that will help our analysis. Is this same information that let the debugger loads it and show us all the information that will help us on the debugging process.

In this PE Header we have many information, like the EntryPoint. EntryPoint like it's name, is the offset where the execution must to begin. This offset belong to the (code, text) section where all the code of our program is in. Again, everything on the file is hex data, but when you put this data on code or text section the OS reads it as instructions to CPU execute. All the rest is hex data too, but it is interpreted in a different way. As I said all depends on how you want to interpret information.

So as I said the executable mainly uses the OS to run, so it will need the libraries on the OS to run it's code. Unless the coder uses the ordinal number to call the API, it's easy to see which api the program uses by looking at the .idata section. IDATA stands for "Import Data" that is the imports the executable do to use on the execution.

On windows each DLL library has specific functionality so you can basically use some program like  CFF Explorer to look at the imports of the PE and google each DLL to see the specifics of each one. In our case it uses the KERNEL32.dll and msvcrt.dll. KERNEL32.dll it's pretty basic with core functions, it's very very common. msvcrt.dll it's the library of C on Windows, so as we are using C it make sense to importing it.

Anyway this is subject to another post, but I just doing a little intro on it. Let's continue our debugging.

Let's debug


After you have downloaded and installed it. Let's open our fresh compiled program. Well, it starts little different from others, not at all.. but a little.
It started at ntdll.dll module, but it's already set the breakpoint on the entry point of the executable (EntryPoint information is in the PE Header).

As I said before the program imports some DLLs to uses it's functionality. This DLLs run with our executable so each one of these DLLs and also our executable is a module running. In this case the ntdll.dll was imported by KERNEL32.dll because the the DLL itself uses the ntdll.dll that does some interface with the kernel.

Let's continue. In the x64dbg goes to the Breakpoints tab and look at the breakpoints:



Shortcuts used in this post:


  • F9: Run the program to the end if it doesn't find any breakpoint ahead.
  • F8: Step by step or Line by line.
  • F7: Step into. If there is any CALL instruction you are going inside the CALL. If you F8 then you jump to the next line and skip the CALL.


Ignore the TLS Callback for now, we will not need it in this topic. To do this you go to Options=>Preferences=>[Tab]Events and uncheck the "TLS Callbacks*". I will bring this in the future posts. You can uncheck it or you can simply ignore it skipping with F9.

As you can see the address 0x4012E0 holds our entry point, so lets play until it stops on that address. Press F9 until you reach the address. This is the entry point on programs compiled with GCC, so our program starts after all the initialization code. My tip is to step through it to familiarize with the debugger.

But to make it shorter the call for our program block is on 0x401280 with a CALL instruction to the address 0x401460 (this is generally where the GCC starts to write our program assembly).



So let's do a little analysis. First it set the stack frame (see Assembly Basics) then it enlarges the stack frame by doing an AND followed by a SUB, then it calls a sample.sub_401970 at 0x401469 it's only check for some value at address 0x407028. If you go to the Memory tab you can see that (this information came from PE Header) the address 0x407000 is of the section .bss (uninitialized data), anyway doesn't do anything crucial and we know that, because we write it.

After this step, it move the address 0x405064 to the stack directly it doesn't uses any register to keep this value, it just MOV to the stack and call the PUTS API from the C library of the Windows. Now, why it uses puts if we write printf ? And why it calling from sample.puts ?

First question, if you see the difference from puts to printf you see why it uses the puts. Reference to the puts:




As you can see, the puts receives a pointer to a string then it put a newline character at the end of the string and that was exactly what we did in our code, but with printf. So the GCC just saw it and make it better.

Second question, if you press F7 you will step into the CALL and will see that inside the call it's just a Table JUMP to the original API. No secrets.

That's it. So we could see what the compiler can do with code, it work on it to make it simpler and "faster" in it's own way. So coding and see how compiler handles our code it's good to a better understating of assembly in practice.

I coded a simple program in C that have many ways to bypass, so the goal is to the reach the ultimate function which prints "You reach the secret stuff!!". I recommend that you do not see what it does and try to understand what it is doing and how to bypass it through x64dbg (or any other debugger). I will do a post explaining how to do it and how to patch it. Consider as an exercise. (The program is buggy, I will show why on the next post)




Any doubts, comments, tips, criticism just tell me. We are all here to learn with each other. Hope that's can be useful to anyone. I will bring some other analysis here very soon. Thanks! Bye!

Friday, June 23, 2017

Basics of Assembly

Introduction to Assembly

Hello everyone, it's me again bringing some basic stuff. Even being a basic stuff I hope that can help anyone. I am making this basic posts to my incoming ones, I will bring more technical analysis. Sorry for any mistakes that I maybe did on this post and if I did any, please send me a feedback.
Well, the assembly code it's the "only" way on reversing engineering. Or you interpret assembly mnemonics or you analyze opcodes (machine code). As said in the previous introductory topic (if you didn't read, I do recommend) the assembly code it's generated by the compiler for every code language that you use. So, understanding it is vital to RE. Assembly language doesn't is standart for all assemblers, the mnemonics(instructions) are different deppending of your processor architecture. Since the processor is made of several circuits and each processor has your own cricuits, the logic behind it's processing differs from each other. So the instructions that they "understand" is different from each processor architecture. In this blog I will give the approach of IA-32 architecture. I will not "teach", is more like an approach of what it is and how we work with. So knowing how the computer "works", as Memory-Data X Instruction-Operation. Logically the computer stocks all data on memory and all this data is interpreted and executed by the CPU.

 
Computer / Memory, CPU, IO Devices and BUS

The processor have some pointers to help the CPU keep track of what it need to do with what data. Then we have the instruction pointer and the data pointer. Through the posts we will see it in practice. So the instruction pointer points to the memory block that represents an instruction and the data pointer to a memory block that represents the data, then the CPU executes the instruction with the data that is pointed.

 
CPU Units X Memory

These pointers allocate the memory offsets in registers. As the processor executes these instructions the instruction pointer goes to the next instruction and the data pointer too. The instruction has between 1-3 bytes and is called opcode (operation code). So basically assembly has three "parts", opcode mnemonics, data sections and directives.

Opcode


Mnemonic code is the "english" representation of the instruction code, e. g. the '89' instruction is the 'mov' mnemonic. Different assembly types represent instructions differently.

 
OllyDbg / Right Assembly, Left OpCodes

Data


The data sections is the space used to store the data which the instrunction will use to execute, so this data can be in some memory section or it can use the stack (memory area, more later). All the data is stored in the hex representation and is referenced by it's memory address. So every data stored on the system has a memory address, it can be a immediate constant in the assembly code or it can be stored on the stack frame.

Directives


Directives are the elements used in assembly to tell the assembler (which compiles the assembly) how to interpret this type of data, data includes everything, like code and values. For example if you want to store a float value the assembler needs to know, then it can reserve memory properly. One of the important directives of assembly is the ".section" directive. This directive creates sections on memory for each type of data.

Sections


We can have any kind of section we want, but all programs have this by default:

  • .text:
    • All the code instructions are alocated in this section. No data is allowed here, except some fixed data of variables like a = 5, but that depends of the programmer on low-level programming and depends of the compiler on high-level programming.
  • .data:
    • This section is responsible for stores all data that the .text request. It will be referenced as an address in the .text section, like program.ADDRESS.
  • .bss:
    • This section generally used to unitialized data. I think the name might change from language to language, don't sure.


The IA-32 Architecture


The IA-32 architecture was designed for pentium processors by Intel. I don't know for sure if it is the most used nowdays, but it's a very known one and have a lot of documentation about it. When you learn assembly basis in one architecture, makes easy to learn in another one, because the base still the same. Some assembly let you do more others let do less, I think it's the basic difference. In my last topic I tried to wrote about computer in general form and I think that you already know how it is. I don't want to make this part too much extensive. So basically IA-32 is divided in 4 parts:

  • Control unit:
    • Control is responsible for bring all the information from memory, data and instructions. Then it decodes this instructions into micro-operations and pass to execution unit. The result of the operation is passed back for control unit that stores the result.
  • Execution unit:
    • Responsible for execute all the micro-operations.
  • Registers:
    • Registers are responsible to keep track of data that are been used. This registers are internal memory of the processor. Having this little memory inside the processor make it much more faster than going outside (from processor itself) searching data in RAM memory and retrieve it.
    • I want to keep it objective so I will not write about all of them. You can read in the book listed on the reference, I do recommend. So there are basically four types of registers (there are more like I said):
      • General Purposes: 8 32-bits registers. They are used to work with data.
      • Segment: 6 16-bit registers. Used to memory access.
      • Intruction Pointer: 1 32-bit register. Points to the next instruction to be executed.
      • Floating-point: 8 80-bit register. It used to work with floating-point numbers.
  • Flags:
    • Flags are used to keep control of the operations executed by processor. It's a way to know if some operation worked or not. There are specific type of flags to specific operations. We will see it.


Registers


General Purposes


These registers are mainly used to work with data as the code is been executed. All data used in the instructions are stored in these registers. They are 32-bits longer at the "top" level (32-bits), but it can be sliced in minor parts (16-bits, 8-bits) that stores minor data.

  • EAX (32-bits):
    • AH (16-bits):
      • AL (8-bits)
  • EBX (32-bits):
    • BH (16-bits):
      • BL (8-bits)
  • ECX (32-bits):
    • CH (16-bits):
      • CL (8-bits)
  • EDX (32-bits):
    • DH (16-bits):
      • DL (8-bits)
  • EDI (32-bits):
    • DI (16-bits)
  • ESI (32-bits):
    • SI (16-bits)
  • EBP (32-bits):
    • BP (16-bits)
  • ESP (32-bits):
    • SP (16-bits)

OllyDbg / Registers and Flags

These are the 8 32-bits registers that we will work with a lot. So it's important to say that modifing a top level register you will modify the low level register. For example if you put any value at AL and then put a new value on EAX the AL value will be overrided. Some of these registers are used in the default way. EBP and ESP for example are used to control the stack frame. Stack frame is a block of memory used to control some local variables of function/method. But you can use the stack when you need to call a method/function you push the parameter onto the stack so the call instructions can grab these parameters to call the method/function. As we analyze artifacts we will see the pattern of it's usage. Because of this it's important to know programming. The good way to learn it's to code and analyze it. On the later topics I will bring much more pratical examples with C language. It's amazing what we can do (I mean, you are managing energy, bro!! lol).


Segment


The segment registers are used to identify where data is located. Each segment register has a pointer to the section where it suposed to grab the data. The segment registers are:
  • CS: Code Segment.
  • DS: Data Segment
  • SS: Stack Segment
  • ES: Extra Segment
  • FS: Extra Segment
  • GS: Extra Segment
So each one is used in specific cases. For example, if you have a address memory on EAX (of data section) register and you have some data on EBX and want to save it on the .data section you maybe see that:

mov ds:[EAX], EBX

So you are moving the data on the EBX to where [EAX] pointing in the DS section. The [] brackets indicating that is a pointer to some memory address.

 
OllyDbg / Code acessing SS segment


We will see much more in pratical examples. The best way to learn.


Flags


The flags are maintained in a single 32-bits register called EFLAGS and each flag is represented by each bit. So as I said the flags are used to control if the operations that the processor executed worked or not. For example for conditional jumps through the code execution it checks if the Zero Flag (depends on the jump, others can be used) was set so it can know whether it will jump or not. There is an image as you already saw in registers topic. The flags is divided in three groups:

  • Status Flags
  • Control Flags
  • System Flags

I will only discuss about status. If you want to know more, there are books listed in the reference, I do recommend to read. The status flags are used to sign the result of mathematical operations executed by the processor. The flags are:
  • CF: Carry Flag.
    • Carry flag is used to manage the carry or borrow out in mathematical operations. It means that occured an overflow, i. e. there is some remaining data. Used in unsigned arithmetic.
  • PF: Parity Flag.
    • Is set when the result of the operation have sum of the 1's bit even number.
  • AF: Adjust Flag.
    • Used in Binary Coded Decimal (BCD), is set when the result of an operation is a borrow or carry. BCD it's a nice feature to work with decimals, if you want to know more at reference has what you need.
  • ZF: Zero Flag.
    • Is set when the result of an operation is 0.
  • SF: Sign Flag.
    • Is set in the most significant bit, when the operation results in a negative number.
  • OF: Overflow Flag.
    • Is used in signed integer operations and is set when the operation result is too large for positive numbers representation or too small in the negative numbers representation.

Stack


So now we are going to talk about the stack. Stack is very important in the reversing due it's common usage in the assembly world. The stack is a memory area where the program in execution uses to store short-term data. So the stack is generally used to:
  • Save register values
    • You can save the register in the stack to use it for another operation and then retrieve the old value to it.
  • Store local variables
    • Store the local variables at function scope. Like I said before, when doing it the variable is accessed directly using SS segment to access the offset in the stack.
  • Passing function parameters
    • To call a function generally you push all parameters on the stack from the right to left and call the function. For example, f(p1,p2,p3), you will pass p3,p2,p1.
  • Store the return address of the function call
    • The address of the next instruction after the call instruction, doing that the program will know where to back when it executes the retn instruction inside the function called.
Storing locally means that when you enter in a function scope all the local variables generally uses the stack to keep your data. In general everything is on memory, on the address space that the operating system gave us. The stack is just an area on that address space where the program uses to store data. So to put values on the stack you uses push instruction and to retrieve it you uses pop instruction. Everytime you enter a function a stack frame is set. Stack frame is set of addresses reserved to the function in execution, that set is limited by EBP(Base pointer) and ESP ('Top' Stack pointer). Generally this is how you see the stack frame been set:

PUSH EBP
MOV EBP,ESP
SUB ESP, SIZE

 First you save the old EBP, for when you back to the previous function will be able to reset the old stack frame, then you set the new base pointer and add the size (how many addresses) you need to that function. Stack are managed as LIFO type, last in first out. So the last element that you pushed onto the stack is the first element that will be poped out. But you can access this data directly if you need it, remember the SS segement ? So you can access using it together with the ESP (points to the top of the stack) register, like:

mov EAX, PTR SS:[ESP+4]

In the last instruction you moved the value of "ESP (plus) 4" pointing at to the general register EAX.

 Some important things about stack is that it grows up to lower addresses on IA-32 architecture. So bigger the stack is, lower addresses it access as we can see:

 
How stack works basically

In the image we can see the heap too and it's our next topic. This post I am bringing a theorical approach but in the next we will discuss it all in a pratical way. For now lets just abstract.


Heap


Heap is a memory area where the program uses for dynamic allocation. The heap is managed generally by the OS. So when the programmer need some space to store data that is bigger than the stack could manage, then the program store it in the heap memory. So the memory heap is passed to the program when the OS is loading it on memory. When you have a literal expression on your code like:

char newText[] = "Testing how code storing data.";

Regardless the data was inside some function the compiler generally uses the .data section and give to the instruction that will use this data the constant immediate address of the data, something like program.ADDRESS. But when you are loading something external for example, you don't know the size you going to need so the size is dynamic, then the program will have a routine that allocate the size you need in the heap.

 Heap it's important in RE because many program uses it to allocate data and sometimes identify which routine allocates the memory can be useful.

Now I think you are able to understand the incoming new posts that I will bring here. As I post new topics I will try to discuss a little more on technical topics. On the pratical part we will have a better view.

References


  • Google
  • Eldad Eilam - Reversing: Secrets of Reverse Engineering
  • Reverse Engineering Code With IDA Pro
  • Professional Assembly Language - Richard Blum

Windows Objects

Objects in windows are referred as kernel objects . They provide a link or an way to use any objects functionality according with the object...