Código de incorporação e o perigo de software pirateado

Sobre como você pode incorporar código sem jmp na seção de código e permanecer invisível se não estudar o código totalmente desmontado. Quem se importa, por favor, debaixo do gato.

Estou desenvolvendo um desmontador C para Linux. Sobre mim, eu não diria que sou um programador profissional. Não trabalho como programador, mas o que aprendi é a leitura de livros, a invenção de mim mesmo ou o estudo do código-fonte de outros programas. Portanto, se o código lhe parecer infantil, não jure.

Para iniciantes, fiz um desmontador e meu código agora fica assim, ou seja, um byte é lido e passado para a função desejada.

void disasm_intel ( unsigned char *ptr, int size, int byte_order, int show ) { show_asm = show; virt = global_virt_text; unsigned char *start = ptr; start_op = ptr; for ( int index = 0; index < size; index++ ) { if ( show_asm == TRUE ) printf ( "%lx: ", virt ); switch ( *ptr ) { case 0x30: intel_opcode_1_0x30 ( &ptr, &index, byte_order ); break; case 0x31: intel_opcode_1_0x31 ( &ptr, &index, byte_order ); break; case 0x66: intel_opcode_1_0x66 ( &ptr, &index, byte_order ); break; case 0x67: intel_opcode_1_0x67 ( &ptr, &index, byte_order ); break; case 0x83: intel_opcode_1_0x83 ( &ptr, &index, byte_order ); break; case 0x88: intel_opcode_1_0x88 ( &ptr, &index, byte_order ); break; // mov register to register byte case 0x89: intel_opcode_1_0x89 ( &ptr, &index, byte_order ); break; case 0x8a: intel_opcode_1_0x8a ( &ptr, &index, byte_order ); break; case 0x8b: intel_opcode_1_0x8b ( &ptr, &index, byte_order ); break; // mov esp, %x : mov ebp, %x case 0x8d: intel_opcode_1_0x8d ( &ptr, &index, byte_order ); break; // lea case 0xb0: intel_opcode_1_0xb0 ( &ptr, &index ); break; // mov al, %x case 0xb1: intel_opcode_1_0xb1 ( &ptr, &index ); break; // mov cl, %x case 0xb2: intel_opcode_1_0xb2 ( &ptr, &index ); break; // mov dl, %x case 0xb3: intel_opcode_1_0xb3 ( &ptr, &index ); break; // mov bl, %x case 0xb4: intel_opcode_1_0xb4 ( &ptr, &index ); break; // mov ah, %x case 0xb5: intel_opcode_1_0xb5 ( &ptr, &index ); break; // mov ch, %x case 0xb6: intel_opcode_1_0xb6 ( &ptr, &index ); break; // mov dh, %x case 0xb7: intel_opcode_1_0xb7 ( &ptr, &index ); break; // mov bh, %x case 0xb8: intel_opcode_1_0xb8 ( &ptr, &index, byte_order ); break; // mov eax, %x case 0xb9: intel_opcode_1_0xb9 ( &ptr, &index, byte_order ); break; // mov ecx, %x case 0xba: intel_opcode_1_0xba ( &ptr, &index, byte_order ); break; // mov edx, %x case 0xbb: intel_opcode_1_0xbb ( &ptr, &index, byte_order ); break; // mov ebx, %x case 0xbe: intel_opcode_1_0xbe ( &ptr, &index, byte_order ); break; // mov esi, %x case 0xbf: intel_opcode_1_0xbf ( &ptr, &index, byte_order ); break; // mov edi, %x case 0xc3: intel_opcode_1_0xc3 ( ); break; // ret case 0xcd: intel_opcode_1_0xcd ( &ptr, &index ); break; // int 0x%x } ptr++; virt += ptr - start; start = ptr; start_op = ptr; } show_asm = FALSE; } 

E essas funções já são um monte. Em alguns lugares, fiz comentários para capturar a interconexão das instruções da máquina e talvez mais tarde fazer um desmontador mais competente. Mas, neste formulário, no qual tenho o código agora, posso definir facilmente quaisquer condições para cada operador.

E, enquanto fazia isso, tive uma ideia: é possível adicionar código no meio da seção de código? Acontece que você pode, mas em todos os casos? Até agora, para adicionar código, eu uso códigos de máquina já preparados. Se eu puder mais tarde, tornarei o tradutor do assembler em código de máquina para adicionar código mais conveniente. No meu caso, você precisa especificar o deslocamento na seção de código e os bytes são copiados para o lugar certo. Havia também um certo problema: endereçamento na memória. Eu adicionei um código ao comando lea que salva os dados necessários na estrutura e, se você inserir novos operadores na seção de código, todas as compensações serão alinhadas, de modo a indicar dados nas novas compensações. Bem, não é muito difícil, se você inseriu o código, a seção de código aumentou no mesmo número de bytes e todas as outras seções após a seção de código conterão novos desvios. Eu fiz isso para que haja diferenças em onde você cola o código, todas as compensações funcionam corretamente. Surgiu então o problema de que, ao abordar tais

 mov eax, [eax + eax + 0x100] 

O fato é que, em tal endereçamento, pode haver um fluxo e apontar para a pilha, e não para outra seção. Decidi fazer isso para que, se o endereço apontar para a seção de dados, considere as compensações ao inserir o código, se apontar para a pilha, ou seja, não o endereço da seção de dados, e não leve em consideração as compensações.

E dessa maneira os atacantes podem tirar vantagem. Afinal, o código malicioso pode ser inserido no início de alguma função do programa, por exemplo, para que um fork filho seja criado e um arquivo especial seja baixado. No Linux, isso pode ser feito sem problemas. De fato, em / usr / include há um arquivo com todas as funções do sistema operacional. Ou seja, você pode usar a parte de rede, mesmo que o programa não tenha funções de rede. Não sei como, no Windows, mas tentarei adicionar trabalho com o formato pe posteriormente. Pode fazer o mesmo que no Linux. Até agora eu tenho uma versão do console. Mas então pretendo fazer no gtk.

Obrigado por gastar seu tempo no meu artigo.

Source: https://habr.com/ru/post/pt477590/


All Articles