Разборка IDA создает совершенно другой код для файла ASM для исполняемого файла, скомпилированного в Visual Studio 2017 - PullRequest
0 голосов
/ 17 ноября 2018

Я скомпилировал простую программу с использованием Visual Studio 2017

#include <stdio.h>
int main()  
{
    printf("hello, world\n"); 
    return 0; 
}

Я скомпилировал ее с помощью командной строки

cl 1.cpp /Fa1.asm 

Это дает мне ассемблерный код, который (в основном) имеет смысл для меня

; Listing generated by Microsoft (R) Optimizing Compiler Version 19.14.26429.4 



INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

CONST   SEGMENT
$SG5542 DB  'hello, world', 0aH, 00H
CONST   ENDS
PUBLIC  ___local_stdio_printf_options
PUBLIC  __vfprintf_l
PUBLIC  _printf
PUBLIC  _main
PUBLIC  ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA ; `__local_stdio_printf_options'::`2'::_OptionsStorage
EXTRN   ___acrt_iob_func:PROC
EXTRN   ___stdio_common_vfprintf:PROC
;   COMDAT ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA
_BSS    SEGMENT
?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA DQ 01H DUP (?) ; `__local_stdio_printf_options'::`2'::_OptionsStorage
_BSS    ENDS
; Function compile flags: /Odtp
_TEXT   SEGMENT
_main   PROC
; File c:\users\mr dai\documents\michael\study\cybersecurity\reverseengineering4beg\random\random\random.cpp
; Line 3
    push    ebp
    mov ebp, esp
; Line 4
    push    OFFSET $SG5542
    call    _printf
    add esp, 4
; Line 5
    xor eax, eax
; Line 6
    pop ebp
    ret 0
_main   ENDP
_TEXT   ENDS
; Function compile flags: /Odtp
;   COMDAT _printf
_TEXT   SEGMENT
__Result$ = -8                      ; size = 4
__ArgList$ = -4                     ; size = 4
__Format$ = 8                       ; size = 4
_printf PROC                        ; COMDAT
; File c:\program files (x86)\windows kits\10\include\10.0.17134.0\ucrt\stdio.h
; Line 954
    push    ebp
    mov ebp, esp
    sub esp, 8
; Line 957
    lea eax, DWORD PTR __Format$[ebp+4]
    mov DWORD PTR __ArgList$[ebp], eax
; Line 958
    mov ecx, DWORD PTR __ArgList$[ebp]
    push    ecx
    push    0
    mov edx, DWORD PTR __Format$[ebp]
    push    edx
    push    1
    call    ___acrt_iob_func
    add esp, 4
    push    eax
    call    __vfprintf_l
    add esp, 16                 ; 00000010H
    mov DWORD PTR __Result$[ebp], eax
; Line 959
    mov DWORD PTR __ArgList$[ebp], 0
; Line 960
    mov eax, DWORD PTR __Result$[ebp]
; Line 961
    mov esp, ebp
    pop ebp
    ret 0
_printf ENDP
_TEXT   ENDS
; Function compile flags: /Odtp
;   COMDAT __vfprintf_l
_TEXT   SEGMENT
__Stream$ = 8                       ; size = 4
__Format$ = 12                      ; size = 4
__Locale$ = 16                      ; size = 4
__ArgList$ = 20                     ; size = 4
__vfprintf_l PROC                   ; COMDAT
; File c:\program files (x86)\windows kits\10\include\10.0.17134.0\ucrt\stdio.h
; Line 642
    push    ebp
    mov ebp, esp
; Line 643
    mov eax, DWORD PTR __ArgList$[ebp]
    push    eax
    mov ecx, DWORD PTR __Locale$[ebp]
    push    ecx
    mov edx, DWORD PTR __Format$[ebp]
    push    edx
    mov eax, DWORD PTR __Stream$[ebp]
    push    eax
    call    ___local_stdio_printf_options
    mov ecx, DWORD PTR [eax+4]
    push    ecx
    mov edx, DWORD PTR [eax]
    push    edx
    call    ___stdio_common_vfprintf
    add esp, 24                 ; 00000018H
; Line 644
    pop ebp
    ret 0
__vfprintf_l ENDP
_TEXT   ENDS
; Function compile flags: /Odtp
;   COMDAT ___local_stdio_printf_options
_TEXT   SEGMENT
___local_stdio_printf_options PROC          ; COMDAT
; File c:\program files (x86)\windows kits\10\include\10.0.17134.0\ucrt\corecrt_stdio_config.h
; Line 85
    push    ebp
    mov ebp, esp
; Line 87
    mov eax, OFFSET ?_OptionsStorage@?1??__local_stdio_printf_options@@9@4_KA ; `__local_stdio_printf_options'::`2'::_OptionsStorage
; Line 88
    pop ebp
    ret 0
___local_stdio_printf_options ENDP
_TEXT   ENDS
END

Однако я открываю exe с IDA, и дизассемблер выплевывает что-то совершенно неразборчивое.

ida_cap

Почему это так?Визуальная студия автоматически скрывает ассемблерный код по умолчанию?Я погуглил, но, похоже, это не так.Если да, то как отключить запутывание?

Спасибо

1 Ответ

0 голосов
/ 17 ноября 2018

main не является точкой входа вашей программы на этом уровне.

Язык C является абстракцией, прежде чем main сможет запустить , необходимо инициализировать среду выполнения .
C ++ еще сложнее, но идея та же: есть какой-то код, который запускается до main (в противном случае, кто, например, инициализировал бы cout?)

В конце днявсе языки компилируются в двоичный PE, важно ознакомиться с этим.

Я скомпилировал вашу программу, чтобы показать, как найти main.
Обратите внимание, что, основываясь наВаш код, я предположил, что вы компилировали файл C, глядя на разборку, кажется, вы скомпилировали файл C ++.C ++, как известно, более сложен для обратного инжиниринга.

Пример ниже будет отличаться от вашего, мой пример представляет собой отладочную сборку x86.


Прежде всего, IDA сообщает вам, где находится точка входа PE в закладке Экспорт

PE entry-point in the Exports tab

Если дважды щелкнуть по нему и следовать пути, следуя инструкциям jmp и call (есть только один путь, вы не можете потеряться), вы получите процедуру с двумя вызовами

Init and body

VS генерирует cookie-файл безопасности в первую очередь, и именно это делает первая вызванная функция:

Security cookie

Обратите внимание, что эта подпрограмма довольно узнаваема даже без подсказок IDA, потому что она делает очень точные вызовы API, вы можете найти некоторые из названий функций на картинке, чтобы найти документацию.

Предполагается, что этоЭто процедура генерации cookie-файлов безопасности, после чего мы возвращаемся к предыдущему и вводим второй вызов

Body

Это тело вашей программы, а не main, но если CRT инициализируется и завершается, включая вызов main.
Takeпосмотрите на блок-схему в левом нижнем углу и увидите, что большая часть работы находится в левой ветви (это означает, что правая ветвь является ошибочным условием).

main обычно называют за несколько call с до _exit или _cexit.Затем мы приближаемся к этим вызовам:

Candidate calls

Если вы наведите курсор мыши на вызов функции, IDA покажет код функции.
Функции, которые являютсяодиночные jmp присутствуют в сборке отладки, чтобы помочь отладчику, и чаще всего являются функциями времени выполнения.
Первая обведенная функция, когда она находится, показывает вызов подпрограммы «enviroment», это хорошо, так как main нужны аргументы программы (Windows не передает аргументы программе, для их получения существует специальный API).

Pre main

Thisвыглядит как вызов main, аргументы совпадают.
Фактически, если мы введем вызов, мы получим main:

main


Конечно, вы могли бы найти main, просто взглянув на "Hello, world!"строка в «String view» ( Shift + F12 ), но в реальном мире сценарий обратного инжиниринга это почти всегда невозможно.

Создание программы, а затем ее обратное проектирование - очень хороший подход. Если у вас установлена ​​VS, вы можете иметь MS DIA SDK, который позволяет IDA читать файлы pdb.
Это очень помогает с реверс-инжинирингом, вы можете загрузить две IDA, одну с PDB, а другую без и сравнить.
К сожалению, получить MS DIA SDK может быть не так просто.

Кроме того, IDA FLIRT является обязательным.
Это библиотека сигнатур методов, она позволяет IDA распознавать функции времени выполнения, что позволяет легко сосредоточиться на реальном коде приложения.Трудно найти (и сложнее создать) подпись, хотя они того стоят.


Наконец, обратите внимание, что отладочная сборка может быть сложнее для обратного инжиниринга из-за типа сгенерированного кода.
Если вы сделаете сборку релиза и перепроектируете ее, вы увидите, что прощедобраться до main.

...