Decodificando Strings em Malwares


Todos os dias são criadas novas técnicas para dificultar a investigação de códigos maliciosos. A primeira barreira que encontramos são os packers de executáveis que dificultam bastante a análise estática.

Transcorrido esse obstáculo o caminho ainda não está livre, geralmente as strings mais relevantes do código como por exemplo endereços de e-mails, URLs, hosts e servidores de banco de dados, estão com uma espécie de criptografia, codificação ou obfuscação. Chamarei de criptografia.

Essa criptografia pode ser desde simples trocas de letras até complexas operações matemáticas. Nesse artigo farei um estudo de caso de um padrão de criptografia que encontrei em alguns malwares.

Nesse em questão havia mais de 2.200 strings criptografadas, conseguir revertê-las possibilitaria um entendimento significativo sobre o malware.

Uma característica da criptografia em malwares é que sempre a função de descriptografia estará dentro dele, se a string de um e-mail for algo do tipo “G5t64gKwiYJU8ht5shtXhzp72HtY” o malware só vai conseguir enviar o e-mail se essa string for transformada no endereço real antes.

Primeiramente farei a análise do código (dis)Assembly da função de descriptografia, depois com o entendimento da mesma mostrarei como poderia ser criado um programa para fazer o mesmo trabalho e descriptografar todas as strings de uma só vez.

Identificando o problema

Como em todas as análises o primeiro passo é identificar o executável do malware para descobrir a presença de packers e a linguagem de programação. Nesse caso o arquivo não possuía proteções e a linguagem utilizada foi MS Visual Basic 5.0 ou 6.0.


Ao abrir o arquivo no OllyDbg e fazer a busca por strings foi possível notar que muitas delas possuíam uma espécie de criptografia.


Ao analisar o código onde essas strings criptografadas eram utilizadas notei um padrão que se repetia, todas faziam uma chamada: CALL pernet.00444230. Então possivelmente essa seria a função de descriptografia, quando o malware precisava usar a string antes descriptografava para obter o texto verdadeiro dela.

Foi possível comprovar isso colocando um breakpoint após a chamada da função para pegar o retorno, ou seja, a string descriptografada.


Criptografada: "nDfL0+AGnDKL0+PLna5LnaAOnaKGJa02nPqG5aPdnDvL5602"
Descriptografada: "G_DB_USUARIO_AVISO"

A olho nu fica difícil identificar alguma lógica nesse processo, vamos partir para a escovação de bits para descobrir como isso é feito.

Baixando o nível

**************************************************
CHAMADA DA FUNÇÃO
**************************************************

OFFSET  INSTRUÇÃO

00453E3B MOV EDX,pernet.0040F6D8 ; "nDfL0+AGnDKL0+PLna5LnaAOnaKGJa02nPqG5a..."
00453E40 LEA ECX,DWORD PTR SS:[EBP-28]
00453E43 CALL ESI
00453E45 PUSH pernet.004EA1B0 ; "Zm7oWEOh6GLdu9Q4t1gCF"
00453E4A PUSH pernet.004EA1AC ; "w/sDbk2VKcUy5nJTA0paP8"
00453E4F LEA EDX,DWORD PTR SS:[EBP-28]
00453E52 PUSH pernet.004EA1A8 ; "xXqMIifSlBH3Z+vjYNRre"
00453E57 PUSH EDX
00453E58 CALL pernet.00444230

Essa é a chamada da função, os 4 Offsets destacados são os parâmetros que são passados através da pilha, eles são passados na ordem inversa, do 4º para o 1º, serão acessados na função como:

4º [EBP+14] – "Zm7oWEOh6GLdu9Q4t1gCF"
3º [EBP+10] – "w/sDbk2VKcUy5nJTA0paP8"
2º [EBP+C] – "xXqMIifSlBH3Z+vjYNRre"
1º [EBP+8] – "nDfL0+AGnDKL0+PLna5LnaAOnaKGJa02nPqG5aPdnDvL5602"

O 1º parâmetro é a string criptografada, o 2º, 3º e 4º parâmetros são 3 strings que juntas formarão um chave criptográfica que chamarei de KEY, através dela a função consegue descriptografar as strings.

**************************************************
INÍCIO DA FUNÇÃO
**************************************************

00444230 PUSH EBP
00444231 MOV EBP,ESP
00444233 SUB ESP,0C
00444236 PUSH <JMP.&MSVBVM60.__vbaExceptHandler> ; SE handler installation
0044423B MOV EAX,DWORD PTR FS:[0]
00444241 PUSH EAX
00444242 MOV DWORD PTR FS:[0],ESP

Aqui temos o prólogo da função onde o ponteiro da pilha (ESP) é copiado para o EBP que será usado como o ponteiro base, através dele a função acessa as variáveis locais e os parâmetros. As outras instruções criam o manipular de exceções para controlar os erros da função.

00444249 SUB ESP,0B0

Cria espaço na pilha de 176 bytes (0xB0) para variáveis locais.

0044424F PUSH EBX
00444250 PUSH ESI
00444251 PUSH EDI
00444252 MOV DWORD PTR SS:[EBP-C],ESP
00444255 MOV DWORD PTR SS:[EBP-8],pernet.00401828

0044425C MOV EAX,DWORD PTR SS:[EBP+C]
0044425F MOV EDX,DWORD PTR SS:[EBP+10]

Copia o 2º e 3º parâmetro para EAX e EBX respectivamente.

00444262 MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaStrCat>]
00444268 XOR EBX,EBX ; zerou o EBX
0044426A MOV ECX,DWORD PTR DS:[EAX]
0044426C MOV EAX,DWORD PTR DS:[EDX]
0044426E PUSH ECX
0044426F PUSH EAX

Copia o 2º e 3º parâmetro para a pilha

00444270 MOV DWORD PTR SS:[EBP-1C],EBX
00444273 MOV DWORD PTR SS:[EBP-20],EBX
00444276 MOV DWORD PTR SS:[EBP-24],EBX
00444279 MOV DWORD PTR SS:[EBP-2C],EBX
0044427C MOV DWORD PTR SS:[EBP-34],EBX
0044427F MOV DWORD PTR SS:[EBP-44],EBX
00444282 MOV DWORD PTR SS:[EBP-54],EBX
00444285 MOV DWORD PTR SS:[EBP-64],EBX
00444288 MOV DWORD PTR SS:[EBP-74],EBX
0044428B MOV DWORD PTR SS:[EBP-84],EBX
00444291 MOV DWORD PTR SS:[EBP-A4],EBX
00444297 MOV DWORD PTR SS:[EBP-B4],EBX

Zera várias posições na pilha para armazenar variáveis locais.

0044429D CALL ESI ; <&MSVBVM60.__vbaStrCat>

Chama a função vbaStrCat tendo como parâmetros o ECX e EAX que foram colocados na pilha. Essa sequência de instruções mostra bem o papel do compilador na geração do código, vemos que não seguiu uma sequência lógica de colocar os parâmetros na pilha e já chamar a vbaStrCat, antes realizou outras tarefas (zerar a memória), isso é feito pelo compilador para otimizar o código e melhor aproveitar a CPU.

0044429F MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaStrMove>]
004442A5 MOV EDX,EAX

Geralmente o resultado de uma função vem no EAX, aqui o EAX tem a string concatenada com o 2º e 3º parâmetro.

004442A7 LEA ECX,DWORD PTR SS:[EBP-34]
004442AA CALL EDI ; <&MSVBVM60.__vbaStrMove>

Moveu a string concatenada para a posição [EBP-34] da pilha.

004442AC MOV ECX,DWORD PTR SS:[EBP+14]
004442AF PUSH EAX
004442B0 MOV EDX,DWORD PTR DS:[ECX]
004442B2 PUSH EDX
004442B3 CALL ESI
004442B5 MOV EDX,EAX

O ESI ainda aponta para vbaStrCat e aqui é concatenado o 4º parâmetro com as outras duas strings. Agora o EAX aponta para a string final que será a KEY:

"w/sDbk2VKcUy5nJTA0paP8xXqMIifSlBH3Z+vjYNRrezm7oWEOh6GLdu9Q4t1gCF"
3º + 2º + 4º parâmetros

004442B7 LEA ECX,DWORD PTR SS:[EBP-2C]
004442BA CALL EDI

Move a string concatenada para a posição [EBP-2C] na pilha.

004442BC LEA ECX,DWORD PTR SS:[EBP-34]
004442BF CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeStr>]
004442C5 MOV EAX,DWORD PTR SS:[EBP+8]

Copia para EAX o primeiro parâmetro que é a string criptografada.

004442C8 MOV DWORD PTR SS:[EBP-24],EBX
004442CB XOR EDI,EDI
004442CD MOV ECX,DWORD PTR DS:[EAX]
004442CF PUSH ECX
004442D0 CALL DWORD PTR DS:[<&MSVBVM60.__vbaLenBstr>]
004442D6 MOV ECX,EAX

ECX recebe o resultado da função vbaLenBstr que calculou o comprimento da string criptografada.

004442D8 CALL DWORD PTR DS:[<&MSVBVM60.__vbaI2I4>]
004442DE MOV DWORD PTR SS:[EBP-BC],EAX

Copia para a posição [EBP-BC] o tamanho da string criptografada.

004442E4 MOV EAX,1
004442E9 MOV DWORD PTR SS:[EBP-18],EAX

EAX recebe 1 e foi copiado para a posição [EBP-18] que servirá como um contador.

**************************************************
INÍCIO DO LOOP
**************************************************

004442EC CMP AX,WORD PTR SS:[EBP-BC]
004442F3 JG pernet.00444492

Aqui vemos o início de um loop que vai percorrer toda a string criptografada caractere por caractere. É equivalente a esse pseudocódigo:

for(i=1; i<= length(cryptstring); i++)

004442F9 MOV EDX,DWORD PTR SS:[EBP-2C]
004442FC MOV ECX,DWORD PTR SS:[EBP+8]
004442FF MOV DWORD PTR SS:[EBP-9C],EDX
00444305 LEA EDX,DWORD PTR SS:[EBP-44]
00444308 MOVSX EAX,AX
0044430B MOV DWORD PTR SS:[EBP-7C],ECX
0044430E PUSH EDX
0044430F LEA ECX,DWORD PTR SS:[EBP-84]
00444315 PUSH EAX
00444316 LEA EDX,DWORD PTR SS:[EBP-54]
00444319 MOV ESI,2
0044431E PUSH ECX
0044431F PUSH EDX
00444320 MOV DWORD PTR SS:[EBP-A4],8
0044432A MOV DWORD PTR SS:[EBP-3C],1
00444331 MOV DWORD PTR SS:[EBP-44],ESI
00444334 MOV DWORD PTR SS:[EBP-84],4008
0044433E CALL DWORD PTR DS:[<&MSVBVM60.#632>] ; MSVBVM60.rtcMidCharVar

Basicamente o que todas essas linhas fazem é retornar o caractere que está na posição "i" (contador do loop) na string criptografada. No primeiro loop seria o “n”, no segundo o “D” e assim por diante. Um pseudocódigo para isso:

caractere = cryptstring[i]

00444344 LEA EAX,DWORD PTR SS:[EBP-A4]
0044434A PUSH 1
0044434C LEA ECX,DWORD PTR SS:[EBP-54]
0044434F PUSH EAX
00444350 PUSH ECX
00444351 LEA EDX,DWORD PTR SS:[EBP-64]
00444354 PUSH EBX
00444355 PUSH EDX
00444356 MOV DWORD PTR SS:[EBP-AC],1
00444360 MOV DWORD PTR SS:[EBP-B4],ESI
00444366 CALL DWORD PTR DS:[<&MSVBVM60.__vbaInStrVar>]
0044436C PUSH EAX
0044436D LEA EAX,DWORD PTR SS:[EBP-B4]
00444373 LEA ECX,DWORD PTR SS:[EBP-74]
00444376 PUSH EAX
00444377 PUSH ECX
00444378 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarSub>]
0044437E PUSH EAX
0044437F CALL DWORD PTR DS:[<&MSVBVM60.__vbaI2Var>]

Esse bloco de instruções recebe o caractere encontrado e faz uma busca na KEY para descobrir em qual posição da chave está o caractere, lembrando que começa a contar da posição zero.

Exemplos:
1º loop, “n” é o 13º caractere da KEY, em hexadecimal “0xD”
2º loop, “D” é o 3º caractere da KEY, em hexadecimal “0x3”
3º loop, “f” é o 28º caractere da KEY, em hexadecimal “0x1C”

00444385 MOV ESI,EAX
00444387 LEA EDX,DWORD PTR SS:[EBP-64]
0044438A LEA EAX,DWORD PTR SS:[EBP-54]
0044438D PUSH EDX
0044438E LEA ECX,DWORD PTR SS:[EBP-44]
00444391 PUSH EAX
00444392 PUSH ECX
00444393 PUSH 3
00444395 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVarList>]

Libera alguns espaços na pilha.

0044439B ADD ESP,10
0044439E CMP SI,BX
004443A1 JL pernet.00444492

Controle de erro.

004443A7 IMUL DI,DI,40

Os registradores (E)DI e (E)SI tem um papel fundamental na função, são eles que realizam vários cálculos para chegar no resultado final, ou seja a string descriptografada. Aqui o DI é multiplicado por 0x40, um valor “hard-coded” na função.

004443AB MOV AX,WORD PTR SS:[EBP-24]
004443AF JO pernet.00444508

O JO é para controle de erro das operações, Jump if Overflow.

004443B5 ADD DI,SI

Aqui o DI e SI sendo usados.

004443B8 JO pernet.00444508
004443BE ADD AX,6
004443C2 JO pernet.00444508
004443C8 CMP AX,8
004443CC MOV DWORD PTR SS:[EBP-24],EAX
004443CF JL pernet.0044447F

Esse é um trecho muito importante, o AX serve como um “controlador” para permitir que o caractere da string criptografada seja utilizado nos cálculos da descriptografia ou não. Na verdade a cada 3 caracteres um é descartado.

Se o AX for menor que 8 é descartado e inicia um novo loop. No primeiro loop o JL (Jump if Lower) é satisfeito já que o AX tem o valor 6.

004443D5 MOVSX ESI,DI
004443D8 LEA EDX,DWORD PTR SS:[EBP-24]
004443DB SUB AX,8

Instruções importantes envolvendo o ESI, EDI e AX.

004443DF PUSH EDX
004443E0 PUSH ESI
004443E1 JO pernet.00444508
004443E7 MOV DWORD PTR SS:[EBP-24],EAX
004443EA CALL pernet.00445610
004443EF MOV ECX,EAX
004443F1 CALL DWORD PTR DS:[<&MSVBVM60.__vbaI2I4>]
004443F7 MOV EBX,EAX
004443F9 LEA EAX,DWORD PTR SS:[EBP-24]
004443FC PUSH EAX
004443FD PUSH 1
004443FF CALL pernet.00445490

00444404 MOV ECX,EAX
00444406 MOV EAX,ESI
00444408 CDQ
00444409 IDIV ECX

Esse é o trecho mais importante e mais obscuro da função. Chama duas funções externas nos offsets destacados, ao invés de tentar entender o que essas funções fazem resolvi estudar os retornos delas e descobri que segue um padrão. O resultado sempre vai ser 0x10, 0x04 ou 0x01, e depois recomeça a sequência.

A lógica por trás desse bloco é: o ESI é utilizado como o QUOCIENTE de uma divisão e o resultado dessas funções obscuras é o DIVISOR dessa divisão. Então no último trecho é feita uma divisão:

EAX = EAX (ESI) / ECX (0x10, 0x04 ou 0x01)

Ainda, o resto da divisão também é utilizado nos cálculos e é atribuído ao EDX que poderia ser representado pela operação de módulo:

EDX = EAX (ESI) módulo ECX (0x10, 0x04 ou 0x01)

0044440B MOV ECX,EDX
0044440D CALL DWORD PTR DS:[<&MSVBVM60.__vbaI2I4>]
00444413 MOV EDX,DWORD PTR SS:[EBP-20]
00444416 AND BX,0FF
0044441B MOV EDI,EAX
0044441D MOV DWORD PTR SS:[EBP-7C],EDX
00444420 MOV DWORD PTR SS:[EBP-84],8
0044442A JNS SHORT pernet.00444435
0044442C DEC BX
0044442E OR BX,0FF00
00444433 INC BX
00444435 MOVSX EAX,BX
00444438 LEA ECX,DWORD PTR SS:[EBP-44]
0044443B PUSH EAX
0044443C PUSH ECX
0044443D CALL DWORD PTR DS:[<&MSVBVM60.#608>] ; MSVBVM60.rtcVarBstrFromAnsi

Esse trecho pega o resultado da divisão e transforma ele no caractere ASCII equivalente, por exemplo no segundo loop o resultado da divisão foi 0x34, se procurar na tabela ASCII o hexadecimal 0x34 equivale ao caractere “4”. No terceiro loop o resultado da divisão foi 0x37 equivalente ao “7”.

00444443 LEA EDX,DWORD PTR SS:[EBP-84]
00444449 LEA EAX,DWORD PTR SS:[EBP-44]
0044444C PUSH EDX
0044444D LEA ECX,DWORD PTR SS:[EBP-54]
00444450 PUSH EAX
00444451 PUSH ECX
00444452 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarCat>]
00444458 PUSH EAX
00444459 CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrVarMove>]
0044445F MOV EDX,EAX
00444461 LEA ECX,DWORD PTR SS:[EBP-20]
00444464 CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrMove>]
0044446A LEA EDX,DWORD PTR SS:[EBP-54]
0044446D LEA EAX,DWORD PTR SS:[EBP-44]

Nesse bloco é feita a concatenação dos caracteres ASCII que são obtidos como resultado e colocados em um local da pilha. Nos exemplos do “4” e “7”, a string concatenada já estaria “47...”.

00444470 PUSH EDX
00444471 PUSH EAX
00444472 PUSH 2
00444474 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVarList>]
0044447A ADD ESP,0C
0044447D XOR EBX,EBX
0044447F MOV EAX,1
00444484 ADD AX,WORD PTR SS:[EBP-18]
00444488 JO SHORT pernet.00444508
0044448A MOV DWORD PTR SS:[EBP-18],EAX
0044448D JMP pernet.004442EC

Libera a memória, incrementa o contador e faz um Jump incondicional para o início do loop, agora vai pegar o segundo caractere da string criptografada.

**************************************************
FIM DO LOOP
**************************************************

00444492 MOV ECX,DWORD PTR SS:[EBP-20]
00444495 PUSH ECX
00444496 CALL pernet.004457A0
0044449B MOV EDX,EAX
0044449D LEA ECX,DWORD PTR SS:[EBP-1C]
004444A0 CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrMove>]
004444A6 PUSH pernet.004444F2
004444AB JMP SHORT pernet.004444E1
004444AD TEST BYTE PTR SS:[EBP-4],4
004444B1 JE SHORT pernet.004444BC
004444B3 LEA ECX,DWORD PTR SS:[EBP-1C]
004444B6 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeStr>]
004444BC LEA ECX,DWORD PTR SS:[EBP-34]
004444BF CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeStr>]
004444C5 LEA EDX,DWORD PTR SS:[EBP-74]
004444C8 LEA EAX,DWORD PTR SS:[EBP-64]
004444CB PUSH EDX
004444CC LEA ECX,DWORD PTR SS:[EBP-54]
004444CF PUSH EAX
004444D0 LEA EDX,DWORD PTR SS:[EBP-44]
004444D3 PUSH ECX
004444D4 PUSH EDX
004444D5 PUSH 4
004444D7 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVarList>]
004444DD ADD ESP,14
004444E0 RETN

Após o loop haverá uma string concatenada com todos os resultados, no nosso exemplo seria:

"475F44425F5553554152494F5F415649534F"

Nesse trecho final é feita a conversão dessa string novamente para ASCII pegando de dois em dois os caracteres e transformando-os no equivalente em ASCII:

0x47 = G
0x5F = _
0x44 = D
0x42 = B
0x5F = _
0x55 = U
0x53 = S
0x55 = U
0x41 = A
0x52 = R
0x49 = I
0x4F = O
0x5F = _
0x41 = A
0x56 = V
0x49 = I
0x53 = S
0x4F = O

A string é concatenada e retornada através do EAX:

"G_DB_USUARIO_AVISO"

**************************************************
FIM DA FUNÇÃO
**************************************************

Um pouco mais de código

Agora que já “entendemos” o que a função faz, ficou fácil (ou não) escrever um programa que realiza a descriptografia de forma automática.

Peguei todos as strings criptografadas do malware e copiei em um TXT. Como fiz isso? No OllyDbg na opção “Search for – all referenced text strings” copiei tudo para a área de transferência e salvei no TXT, mas nem todas eram criptografadas, fiz uma triagem com ajuda do Excel definindo colunas e linhas. Esse processo levou cerca de 15 minutos.

Criei o código abaixo em Python que lê linha a linha o TXT e imprime a string descriptografada.

import sys

key = "w/sDbk2VKcUy5nJTA0paP8xXqMIifSlBH3Z+vjYNRrezm7oWEOh6GLdu9Q4t1gCF"

def decode(enc):
  i = 0
  loop = 1
  edi = 0x0
  esi = 0x0
  control = 0x0
  dec = ""
  final = ""
  
  while(i<len(enc)):
    esi = key.find(enc[i])
    edi = edi * 0x40
    edi = edi + esi
    control = control + 0x06

    if(control >= 0x08):     
      esi = edi
      control = control - 0x08

      if loop==1:
        divisor = 0x10;
        loop = loop + 1
      elif loop==2:
        divisor = 0x04
        loop = loop + 1
      else:
        divisor = 0x01
        loop = 1
        
      result = esi / divisor
      edi = esi % divisor

      if result>0: dec += chr(result)

    i = i + 1

  i = 0
  
  while(i<len(dec)):
    try:
      if i+1 < len(dec):
        aux = dec[i]+dec[i+1]
      else:
        aux = dec[i]

      aux = chr(int(aux,16))
      final += aux
    except:
      pass

    i = i + 2
  
  return final

def main():
  try:
    f = open(sys.argv[1],"r")
  except:
    print "File not found! Usage: python decrypt.py <file.txt>"
    sys.exit(2)

  for line in f:
    print decode(line)
  f.close()

if __name__ == "__main__":
  main()


A função "decode" faz a mesma coisa que as linhas que vimos em assembly, recebe um string criptografada e retorna ela descriptografada fazendo os mesmos cálculos.

Salvei como “decrypt.py” e para executá-lo redirecionei a saída para um TXT com esse comando:

python decrypt.py encrypted.txt > decrypted.txt


Algumas das strings descriptografadas que foram encontradas:

https://www2.bancobrasil.com.br/aapf/
HKEY_CURRENT_USER\Software\Microsoft\
C:\avenger.txt
\GbPlugin\bb.gpc
http://vivaxmotos.com/data/c_c_s.gif
https://internetbanking.caixa.gov.br/
numeroContratoOrigem
titular
senhaConta
onkeydown
SQLOLEDB
Data Source
Initial Catalog
User ID
Password
Cadastro_Computador Travou Browser


Como eu disse são mais de 2.200 strings criptografadas, infelizmente não terei tempo de analisar o malware com mais cuidado mas se você quiser poderá baixar todos os arquivos envolvidos no caso (senha: crimesciberneticos.com) e continuar a análise.

Conclusão

Esse não é o método mais fácil nem mais rápido para realizar esse tipo de trabalho mas talvez seja o mais desafiante. Uma das dificuldades que tive foi com as funções importadas da biblioteca do Visual Basic MSVBVM60.DLL.

Praticamente não existe documentação dela na Internet e as vezes as funções utilizam um padrão diferente para retornar os resultados, ao invés de ser no EAX é no EAX+8. Caso fosse a biblioteca do C seria bem mais fácil o processo.

O debugger é o melhor amigo nesses casos, poder executar o programa linha a linha e acompanhar os resultados nos registradores e na pilha ajudam muito no entendimento das funções.

Quando estamos analisando um código assembly é muito importante que pensemos de forma mais abrangente, não devemos focar em o que cada linha faz mas sim qual a função de cada bloco de código, como ele seria representado em uma linguagem de alto-nível. 

Geralmente são necessárias várias linhas de assembly para executar uma instrução de apenas uma linha em linguagem de alto-nível. Conseguir fazer essa abstração é essencial na engenharia reversa.

* Baixe todos os arquivos do post aqui - senha: crimesciberneticos.com

Ronaldo P. Lima

3 comentários:

  1. Otimo post, como sempre!

    Continue assim.

    ResponderExcluir
  2. confesso que não entendi tudo...mais ótimo trabalho...

    ResponderExcluir

Related Posts Plugin for WordPress, Blogger...