[tutorial] breakpoint com int3

Postagem de conteúdo sobre engenharia reversa e cracking
Post Reply
User avatar
Kodo no Kami
Admin
Admin
Posts: 677
Joined: Fri Jan 02, 2015 1:56 pm
Contact:

[tutorial] breakpoint com int3

Post by Kodo no Kami » Sat Apr 14, 2018 5:24 pm

bom galera muitas vezes precisamos debugar o nosso programa, e muitas vezes essa debugação é bem trabalhosa, as vezes necessitando localizar determinado endereço na memoria para conseguir colocar um breakpoint naquela parte que vamos analisar. Uma forma bastante simples de colocar um breakpoint sem precisar ficar lendo instruções do nosso código na memoria é pela interrupção 3 (int 3). O int 3 é um breakpoint da própria arquitetura x86, então tambem existe um código binário próprio para chamar o int 3. Temos que ficar ciente também que não é possível chamar o int 3 fora de uma debugação, vai crashar o programa. Uma forma da gente usar o int 3 é via asm inline chamando a instrução int com o valor 3

Code: Select all

#include <stdio.h>

int main(void){
   printf("exemplo int3\n");
   __asm__("int $0x3");
   printf("by kodo no kami\n");
}
podemos colocar vários int 3 no nosso código, a cada trecho que a gente precisar

Code: Select all

#include <stdio.h>

int main(void){
   printf("exemplo int3\n");
   __asm__("int $0x3");
   printf("by kodo no kami\n");
   __asm__("int $0x3");
}
se a gente executar esse programa fora do debugador vai dar erro

Image

por outro lado se ele for aberto em um debugador e executado la dentro vai parar exatamente no primeiro breakpoint

Image

depois disso bastaria continuar a execução

Image

o mesmo poderia ser feito em outro debugador tambem, não necessariamente precisaria ser o gdb

Image

como também é possível fazer em outras linguagens ou IDEs, como exemplo o delphi

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);
begin
  asm
     int $3
  end;
end;
Image

outra forma da gente usar ele, é colocando o byte equivalente ao int 3, sendo que esse byte é o codigo hexadecimal 0xcc

Code: Select all

#include <stdio.h>

int main(void){
   printf("exemplo int3\n");
   __asm__(".byte 0xcc");
   printf("by kodo no kami\n");
   __asm__(".byte 0xcc");
}
existe uma diferença entre usar a instrução "int 0x3" e colocar diretamente o byte 0xcc. Essa pequena diferença entre os dois são apenas no byte gerado, ja o resultado final é o mesmo ou seja um breakpoint no nosso codigo. Quando colocamos 0xcc vai ter apenas um byte para o breakpoint int 3, quando usamos a instrução "int 0x3" vai gerar dois bytes sendo um equivalente a instrução "int" (0xcd) e o outro equivalente ao valor 0x3 (0x3). Sendo assim também é possível conseguir essa mesma interrupção adicionando os bytes 0xcd e 0x03 no lugar do 0xcc

Code: Select all

#include <stdio.h>

int main(void){
   printf("exemplo int3\n");
   __asm__(".byte 0xcd,0x03");
   printf("by kodo no kami\n");
   __asm__(".byte 0xcd,0x03");
}
no windows existe a função DebugBreak que funciona de forma semelhante

Code: Select all

#include <stdio.h>
#include <windows.h>

int main(void){
   printf("exemplo int3\n");
   DebugBreak();
   printf("by kodo no kami\n");
   DebugBreak();
}
também podemos usar a função IsDebuggerPresent no windows para saber se o programa está sendo debugado

Code: Select all

#include <stdio.h>
#include <windows.h>

int main(void){
   printf("exemplo int3\n");
   if(IsDebuggerPresent()){
	DebugBreak();
   }
   printf("by kodo no kami\n");
   if(IsDebuggerPresent()){
	DebugBreak();
   }
}
já no linux uma função semelhante ao DebugBreak é o __buitin_trap

Code: Select all

#include <stdio.h>
#include <unistd.h>

int main(void){
   printf("exemplo int3\n");
   __builtin_trap();
   printf("by kodo no kami\n");
   __builtin_trap();
}
Image

bom galera a interrupção 3 é utilizada muito para debugação dos programas ou ate mesmo na criação de um debugger, embora tambem seja bastante utilizada de forma maliciosa em malwares para criar hooks e anti-debuggers ^^

by kodo no kami
Image

Conheça o sistema e manipule ele, se limite ao sistema e seja manipulado por ele ~kodo no kami

meu perfil yahoo

LF337
Membro
Membro
Posts: 3
Joined: Mon Apr 16, 2018 5:32 pm

Re: [tutorial] breakpoint com int3

Post by LF337 » Mon Apr 16, 2018 6:17 pm

Só uma correção:
O motivo de int 0x03 gerar um opcode diferente de 0xCC é porque 0xCC é o opcode da instrução int3.

Você acabou se confundindo, o certo é usar int3 para depuração... Alguns debuggers talvez aceitem usar int 0x03 mas só por prever esse equívoco.

O montador Gas do GCC acaba montando as instruções int3 e int 0x03 para o mesmo opcode(0xCC) por já esperar que a pessoa esteja querendo colocar um breakpoint ali. (como é mostrado no print abaixo)
Talvez seja esse o motivo de não ter tido problemas ao usar int $0x3 ao invés de int3.

Image

Eu testei aqui e o gdb não aceita isso. Se você tentar usar int 0x03 no lugar de int3 não vai dar certo.
Como podemos ver no print abaixo:

Image

Em contrapartida o EDB aceitou a instrução int 0x03 como um breakpoint...
Enfim, o correto é usarmos int3. Não devemos confiar na boa vontade do montador ou do debugger para que faça a correção por nós.

EDIT:
Ah, e uma dica que eu dou é criar um macro para não ter que ficar copiando isso tudo.

Code: Select all

#include <stdio.h>

#define breakpoint() __asm__("int3")

int main(){
    breakpoint();
    puts("Oi mundo!");
    return 0;
}

User avatar
Kodo no Kami
Admin
Admin
Posts: 677
Joined: Fri Jan 02, 2015 1:56 pm
Contact:

Re: [tutorial] breakpoint com int3

Post by Kodo no Kami » Tue Apr 17, 2018 1:22 pm

o int3 vai gerar 0xcc assim como o uso do "int 3" vai gerar cd 03 (como eu tinha explicado no post), tanto usar o int 3 e a instrução int3 vai gerar a interrupção 3 (que normalmente é usado para fazer break na debugação, so muitos debugadores usa apenas o 0xcc para fazer esse break como explicado por voce tambem ~ talvez por facilidade ja que é mais simples modificar apenas um byte na memoria), tipo só que isso tambem não muda o fato de muitos debugadores aceitar o cd 03 como break (mesmo prevendo o uso dessa forma é valido usar em alguns debugadores então não é incorreto o uso das duas formas ~ pelo menos nesses debugadores). Como eu disse antes tanto o int3 quanto o int 3 é a interrupção como pode ser visto no codigo a baixo, as 4 formas vai chamar a mesma interrupção ou seja é o int 3

Code: Select all

;nasm -f bin -o kodo.img
;qemu-system-i386 -fda kodo.img

org 0x7c00

mov ax,0
mov fs,ax
mov [fs:12],word kint3hook
mov [fs:14],word 0

int 0x3 ;usando int 0x3
int3    ;usando int3
db 0xcd,0x3 ;usando int 0x3 via bytes
db 0xcc		;usando int3 via byte

fim:
jmp fim

;hook na int 3
kint3hook:
mov si,ktexto
inicio_kint3hook:
cmp [si],byte 0
jz fim_kint3hook
mov ah,0xe
mov al,byte [si]
int 0x10
inc si
jmp inicio_kint3hook
fim_kint3hook:
iret

;dados
ktexto: db "interrupcao int3",0xd,0xa,0x0

times 510-($-$$) db 0x0
dw 0xaa55
Image

o gdb aqui ele funciona sim com cd 03 pode ser que seja o sistema que eu estou usando no caso windows, então aqui tanto faz eu usar o int3, int 3, 0xcc ou 0xcd03 que o resultado vai ser o mesmo o breakpoint desejado

Image
Image

Conheça o sistema e manipule ele, se limite ao sistema e seja manipulado por ele ~kodo no kami

meu perfil yahoo

LF337
Membro
Membro
Posts: 3
Joined: Mon Apr 16, 2018 5:32 pm

Re: [tutorial] breakpoint com int3

Post by LF337 » Tue Apr 17, 2018 2:15 pm

Eu não sei você, mas eu não vejo sentido em usar algo que talvez funcione.
Se eu posso muito bem usar CC que é certeza que vai funcionar, por que usar CD03 que talvez funcione?

E usar int3 e int 0x03 não é exatamente igual. Existem sim algumas diferenças entre as instruções CC e CD03.
Pelo menos de acordo com os manuais da Intel. (link direto para o trecho)

Image

E aqui o print do erro quando eu tento usar CD03:
Image

CC que geralmente é usado como breakpoint de software. Se algum debugger aceita CD03 é um extra dele, não é algo garantido.

User avatar
Kodo no Kami
Admin
Admin
Posts: 677
Joined: Fri Jan 02, 2015 1:56 pm
Contact:

Re: [tutorial] breakpoint com int3

Post by Kodo no Kami » Tue Apr 17, 2018 6:44 pm

sim o uso do int3 (0xcc) é a melhor alternativa nesse caso, so que tambem não quer dizer que o int 0x03 (cd 03) não possa ser usado para fazer o break tambem, ou que o autor tenha se enganado por citar cd 03 como instrução para break (mesmo sendo um extra de alguns debugadores ele totalmente valido e pode ser usado). Sobre a instrução int3 dependendo do compilador ela pode nem existir, veja como exemplo o borland delphi/c++, não tem o int3 como instrução no asm inline deles apenas o "int 0x3" (claro que nesse caso eles gera o byte 0xcc ~ como tambem deve existir compiladores ai que gera os bytes 0xcd03, ou quem sabe ate algum argumento passado para o gcc que permite fazer isso kkk). Outro exemplo que voce citou foi o gas que converte o "int 0x3" para 0xcc direto por isso que da o breakpoint e tal, so que se compilar com o nasm o "int 0x3" ele vai gerar cd 03, ou seja essa conversao depende exclusivamente do compilador e tal
Image

Conheça o sistema e manipule ele, se limite ao sistema e seja manipulado por ele ~kodo no kami

meu perfil yahoo

Post Reply

Return to “Engenharia Reversa / Cracking”