gzn Posted April 18, 2018 at 01:19 PM Share Posted April 18, 2018 at 01:19 PM Se vocês puderem apresentar as soluções mais triviais de se fazer isso acho que muitos iniciantes agradecerão! rs Começando da situação mais simples à mais complicada: Situações: Fácil : Ligado dinamicamente e sem símbolos. Um pouco difícil : Ligado estaticamente e sem símbolos! Muito difícil : Ligado estaticamente, sem símbolos e com um protector popular no mercado!! Analisando um ELF na situação 1. parece que é fácil, é só procurar pelo símbolo __libc_start_main, colocar um bp nele e observar o primeiro argumento. Mas aí eu pensei: e no caso 2. em que nós não temos símbolos e a libc está dentro do nosso binário? E se fosse um PE, quais dicas você daria para as situações acima? Obs.: a situação número 3 se vocês não quiserem comentar deixem de lado, é um tanto difícil de dar dicas visto que não especifiquei nenhum protetor específico (aliás, nem sei quais existem e muito menos os mais populares! rs). Era só pra vocês comentarem quais seriam as técnicas gerais para se chegar na main (ex., como você começaria a analisar o binário e que tipo de técnicas você usaria como por exemplo assinaturas, algoritmos de comparação de código que procuram similaridades com funções previamente conhecidas, o uso de estatística e probabilidade, inteligência artificial, etc.). Participe e comente o que você faria em cada situação! Link to comment Share on other sites More sharing options...
Felipe.Silva Posted April 18, 2018 at 10:58 PM Share Posted April 18, 2018 at 10:58 PM Você quer dizer com um debugger ou software automatizado? No debugger eu encontro a main "na mão" mesmo. O entry point aponta para _start. O primeiro call dentro de _start é para __libc_start_main. O primeiro argumento para __libc_start_main é o endereço da main. Você pode pegar esse endereço sendo passado para ele ou acompanhar a execução até a hora que ele dá call na main. Para x64 ele passa o primeiro argumento em rdi, e eu vi aqui que __libc_start_main preserva esse valor na pilha em [rsp+24] Mais para frente ele pega o endereço da main e joga em rax, e depois dá call rax. Como podemos ver no print abaixo: Mas como eu já disse, o primeiro argumento é o endereço da main. Se você quer pegar o endereço com uma ferramenta automática, eu pegaria daí. Veja rdi recebendo o endereço da main: A seta verde está bem no entry point, isto é, no início de _start. Se eu fosse fazer uma ferramenta eu pegaria o entry point e a partir dele buscaria pelo call. Ao achar o call, os 4 bytes anteriores é o endereço da main. Se assumirmos que o código de _start nunca muda, então nem precisaríamos fazer uma busca. É só calcular entry_point + 0x20 Só que claro, o endereço "raw" e não virtual. Link to comment Share on other sites More sharing options...
gzn Posted April 19, 2018 at 01:05 AM Author Share Posted April 19, 2018 at 01:05 AM 3 horas atrás, Felipe.Silva disse: Você quer dizer com um debugger ou software automatizado? No debugger eu encontro a main "na mão" mesmo. O entry point aponta para _start. O primeiro call dentro de _start é para __libc_start_main. O primeiro argumento para __libc_start_main é o endereço da main. Você pode pegar esse endereço sendo passado para ele ou acompanhar a execução até a hora que ele dá call na main. Para x64 ele passa o primeiro argumento em rdi, e eu vi aqui que __libc_start_main preserva esse valor na pilha em [rsp+24] Mais para frente ele pega o endereço da main e joga em rax, e depois dá call rax. Como podemos ver no print abaixo: Mas como eu já disse, o primeiro argumento é o endereço da main. Se você quer pegar o endereço com uma ferramenta automática, eu pegaria daí. Veja rdi recebendo o endereço da main: A seta verde está bem no entry point, isto é, no início de _start. Se eu fosse fazer uma ferramenta eu pegaria o entry point e a partir dele buscaria pelo call. Ao achar o call, os 4 bytes anteriores é o endereço da main. Se assumirmos que o código de _start nunca muda, então nem precisaríamos fazer uma busca. É só calcular entry_point + 0x20 Só que claro, o endereço "raw" e não virtual. Bacana meu amigo! Você comentou sobre a situação 1. (aquela situação que eu até comentei em que simplesmente poderíamos pegar o primeiro argumento de __libc_start_main). Agora, minha dúvida mesmo é situação nº 2 [em diante] onde você pega um binário estático! Um pouco difícil : Ligado estaticamente e sem símbolos! Por exemplo: na sua máquina tenta fazer esse procedimento acima que você sugeriu no binário ola_mundo.static que você consegue com o seguinte código: https://github.com/gu10ng1t/re/tree/master/bin É só clonar o repo, dar cd em bin/ e digitar make. Muito obrigado pelo post amigo, achei muito bacana o seu passo a passo! Tenta tenta fazer esse "desafio" e compartilha com a gente o que você acha que daria para fazer pra achar a main de maneira que você pudesse aplicar essa técnica em outros binários compilados assim estaticamente e sem símbolos. Link to comment Share on other sites More sharing options...
gzn Posted April 19, 2018 at 02:32 AM Author Share Posted April 19, 2018 at 02:32 AM @Felipe.Silva realmente você está certo! Até para resolver no caso de um binário estático (pelo menos se for fazer o binário da forma tradicional com libc). Parece mesmo que esse deslocamento da entrada+0x20 não varia muito não (pelo menos, até agora nos meus testes não vi nada diferente). Obs.: essa técnica parece funcionar melhor só em casos em que é usada a instrução mov (ex.: mov rdi, 0xFFF...). Algumas vezes nesse ponto (próximo a entrada+0x20) é usado LEA ao invés de MOV, nesse caso essa técnica precisa ser adaptada. Link to comment Share on other sites More sharing options...
gzn Posted April 19, 2018 at 03:34 PM Author Share Posted April 19, 2018 at 03:34 PM Meus amigos, gostaria que alguém desse um exemplo para situação nº 3. Alguém pode escolher um protetor (protector) de binário popular para linux ou windows e dizer mais ou menos as etapas para se chegar a main? Não vale usar o UPX porque ele só comprime os dados! thank you Link to comment Share on other sites More sharing options...
Felipe.Silva Posted April 19, 2018 at 09:20 PM Share Posted April 19, 2018 at 09:20 PM 19 horas atrás, gzn disse: @Felipe.Silva realmente você está certo! Até para resolver no caso de um binário estático (pelo menos se for fazer o binário da forma tradicional com libc). Parece mesmo que esse deslocamento da entrada+0x20 não varia muito não (pelo menos, até agora nos meus testes não vi nada diferente). Obs.: essa técnica parece funcionar melhor só em casos em que é usada a instrução mov (ex.: mov rdi, 0xFFF...). Algumas vezes nesse ponto (próximo a eip+0x20) é usado LEA ao invés de MOV, nesse caso essa técnica precisa ser adaptada. Como eu disse: « Se eu fosse fazer uma ferramenta eu pegaria o entry point e a partir dele buscaria pelo call. Ao achar o call, os 4 bytes anteriores é o endereço da main » Falei do +0x20 somente se assumirmos que _start nunca muda. Se é o caso de mudar, então podemos procurar pelo call. (só procurar por FF 15) De acordo com os manuais da Intel o valor imediato sempre ficará em ultimo(como podemos ver aqui). Então não importa que instrução seja usada, desde que ela esteja logo antes do call vai funcionar. (e se o call não mudar também) Eu fiz um script em Python aqui. Testei no programa que você passou e em um Olá mundo. Nos dois funcionou tranquilo. Link: https://github.com/Silva97/tools/blob/master/mainsearch.py Faz uns testes ai para ver o que dá. EDIT: Eu fiz um teste aqui com o ls e agora que entendi o que você quis dizer com usar o LEA. Ele usa um endereço relativo de acordo com o valor de RIP... Muda muita coisa. '-' Vou tentar adaptar o algoritmo para identificar isso. Link to comment Share on other sites More sharing options...
Felipe.Silva Posted April 19, 2018 at 10:33 PM Share Posted April 19, 2018 at 10:33 PM @gzn. Feito. Agora o script identifica quando usar a instrução LEA. Testei com o ls e funcionou. Só que com isso nós conseguimos o endereço raw... Endereço na memória não vai rolar. Mas com o endereço raw já nos dar a possibilidade de meter um breakpoint... E quando abrir no debugger nós restauramos a instrução que foi alterada. Em relação a packers eu estou na mesma que você. Não conheço nenhum Se alguém puder ao menos indicar um packer para que a gente possa fazer uns testes... Eu nem sei como um packer funciona. kkkkk Link de novo para o script: https://github.com/Silva97/tools/blob/master/mainsearch.py Link to comment Share on other sites More sharing options...
gzn Posted April 19, 2018 at 11:49 PM Author Share Posted April 19, 2018 at 11:49 PM Muito bacana seu script @Felipe.Silva! Creio que não só eu mas os outros que estão iniciando acharam motivador você escrever esse script e ainda na linguagem python (o que é até bom pra quem ta fazendo o curso Pythonicos!). Citar Em relação a packers eu estou na mesma que você. Não conheço nenhum Se alguém puder ao menos indicar um packer para que a gente possa fazer uns testes...Eu nem sei como um packer funciona. kkkkk kkk é isso aí amigo, quando você souber de um e fizer uns testes não deixa de comenta ai no fórum. Seus posts são muito bem organizados e você tem uma didática legal (a maneira como você explica passo a passo). valeu! Link to comment Share on other sites More sharing options...
Jaguar Posted October 21, 2018 at 05:33 PM Share Posted October 21, 2018 at 05:33 PM Boa tarde amigos , tentei rodar o mainsearch.py em cima de um executável binário e não obtive resposta da main .. esse script roda em Linux 64 bits ? Link to comment Share on other sites More sharing options...
cpuodzius Posted December 10, 2018 at 10:13 PM Share Posted December 10, 2018 at 10:13 PM Legal o post e a discussão, well done! Só uma dúvida de carater preciosista, @Felipe.Silva. Se bem entendi, quando você diz "endereço raw", você está se referindo ao RVA (relative virtual address), seria isso? Aproveitando a deixa: @gzn, não vejo o porquê de linkar estaticamente e sem símbolos faria diferença na hora de achar a função main. Qual seria o impacto disso? Além disso, quando inclui a condição de ser modificado por um "protetor de mercado", você está interessado de achar a main do binário resultante ou do binário "original"? []s! Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.