В этом случае вам нужно отредактировать строку символов, которая передается в printf
, но сначала нам нужно получить ее адрес. посмотрев код вызова printf
, мы увидим что-то вроде этого:
PUSH mymodule.1234567
CALL printf
ADD ESP,4
, поэтому, если мы перейдем по адресу 0x1234567
, через ctrl + g , мы увидим:
01234567 48 65 6C 6C 6F 20 57 6F 72 6C 64 0A 00 00 00 00 Hello World.....
так что теперь вы можете редактировать эту строку по своему усмотрению, если только вы не переполняете доступное пространство и сохраняете нулевой терминатор.
Сохранение изменений зависит от того, как вы загрузили бинарный файл (с помощью присоединения или просто «холодного» просмотра), самый простой способ - через «холодный» просмотр (используя только olly как дизассемблер / ассемблер). Доступ осуществляется через view -> file
, затем щелкните правой кнопкой мыши и выберите disassemble
из контекстного меню. В этом режиме сохранение выполняется путем щелчка правой кнопкой мыши и выбора save file
из контекстного меню.
В режиме отладчика (он же при подключении) сохранение выполняется с помощью щелчка правой кнопкой мыши и выбора одного из параметров в контекстном меню copy to executable
.
Обновление
Если вы отлаживаете сгенерированный GCC код, он обычно избегает генерации PUSH
и предпочитает помещать переменные непосредственно в стек, используя MOV [ESP+c],c/r/m
. Скомпилировав ваш пример с GCC, вы увидите код, подобный (для main
):
00401AFC /$ PUSH EBP
00401AFD |. MOV EBP,ESP
00401AFF |. AND ESP,FFFFFFF0
00401B02 |. SUB ESP,10
00401B05 |. CALL GCCOllyT.0040182C
00401B0A |. MOV DWORD PTR SS:[ESP],GCCOllyT.00403024 ; ||ASCII "Hello World!"
00401B11 |. CALL <JMP.&msvcrt.puts> ; |\puts
00401B16 |. MOV DWORD PTR SS:[ESP],GCCOllyT.00403031 ; |ASCII "PAUSE"
00401B1D |. CALL <JMP.&msvcrt.system> ; \system
00401B22 |. XOR EAX,EAX
00401B24 |. LEAVE
00401B25 \. RETN
Здесь важно отметить, что GCC оптимизировал вызов на printf
для вызова на puts
. В таком случае, когда вы знаете искомую строку, вы можете использовать olly в режиме отладчика, щелкнуть правой кнопкой мыши и выбрать search for -> all referenced text strings
, затем просто выбрать нужную строку из списка, чтобы найти код, использующий ее, или следовать его адрес, чтобы найти запись в разделе .data
, чтобы вы могли изменить его. Более длинный способ найти это - использовать бинарный поиск, доступный из контекстного меню, вызываемого правой кнопкой мыши, но обычно это пустая трата текстовых строк.
И чтобы охватить все базы, давайте предположим, что нам нужно было получить код с точки входа.
Если мы перейдем к коду из точки входа модуля, мы будем следовать цепочке следующим образом:
GCCOllyT.<ModuleEntryPoint> 0> $ >PUSH EBP
0040126D . >MOV EBP,ESP
0040126F . >SUB ESP,18
00401272 . >MOV DWORD PTR SS:[ESP],1
00401279 . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>; msvcrt.__set_app_type
0040127F . >CALL GCCOllyT.00401000
00401284 . >PUSH EBP
00401285 . >MOV EBP,ESP
00401287 . >SUB ESP,18
0040128A . >MOV DWORD PTR SS:[ESP],2
00401291 . >CALL DWORD PTR DS:[<&msvcrt.__set_app_type>; msvcrt.__set_app_type
00401297 . >CALL GCCOllyT.00401000
0040129C $ >PUSH EBP
0040129D . >MOV EBP,ESP
0040129F . >SUB ESP,8
004012A2 . >MOV EAX,DWORD PTR DS:[<&msvcrt.atexit>]
004012A7 . >LEAVE
004012A8 . >JMP EAX
отсюда мы видим единственный жизнеспособный вызов как GCCOllyT.00401000
, после чего мы оказываемся здесь (это GCC mainCRTstartup
):
00401000 /$ >PUSH EBP
00401001 |. >MOV EBP,ESP
00401003 |. >PUSH EBX
00401004 |. >SUB ESP,34
00401007 |. >MOV EAX,DWORD PTR DS:[403038]
0040100C |. >TEST EAX,EAX
0040100E |. >JE SHORT GCCOllyT.0040102C
00401010 |. >MOV DWORD PTR SS:[ESP+8],0
00401018 |. >MOV DWORD PTR SS:[ESP+4],2
00401020 |. >MOV DWORD PTR SS:[ESP],0
00401027 |. >CALL EAX
00401029 |. >SUB ESP,0C
0040102C |> >MOV DWORD PTR SS:[ESP],GCCOllyT.00401110 ; |
00401033 |. >CALL <JMP.&KERNEL32.SetUnhandledExceptionFilter> ; \SetUnhandledExceptionFilter
00401038 |. >PUSH EAX
00401039 |. >CALL GCCOllyT.004013CC
0040103E |. >CALL GCCOllyT.004014AC
00401043 |. >MOV DWORD PTR SS:[EBP-10],0
0040104A |. >LEA EAX,DWORD PTR SS:[EBP-10]
0040104D |. >MOV DWORD PTR SS:[ESP+10],EAX
00401051 |. >MOV EAX,DWORD PTR DS:[402000]
00401056 |. >MOV DWORD PTR SS:[ESP+C],EAX
0040105A |. >LEA EAX,DWORD PTR SS:[EBP-C]
0040105D |. >MOV DWORD PTR SS:[ESP+8],EAX
00401061 |. >MOV DWORD PTR SS:[ESP+4],GCCOllyT.00404004
00401069 |. >MOV DWORD PTR SS:[ESP],GCCOllyT.00404000
00401070 |. >CALL <JMP.&msvcrt.__getmainargs>
00401075 |. >MOV EAX,DWORD PTR DS:[404018]
0040107A |. >TEST EAX,EAX
0040107C |. >JNZ SHORT GCCOllyT.004010C8
0040107E |> >CALL <JMP.&msvcrt.__p__fmode>
00401083 |. >MOV EDX,DWORD PTR DS:[402004]
00401089 |. >MOV DWORD PTR DS:[EAX],EDX
0040108B |. >CALL GCCOllyT.004015E4
00401090 |. >AND ESP,FFFFFFF0
00401093 |. >CALL GCCOllyT.0040182C
00401098 |. >CALL <JMP.&msvcrt.__p__environ>
0040109D |. >MOV EAX,DWORD PTR DS:[EAX]
0040109F |. >MOV DWORD PTR SS:[ESP+8],EAX
004010A3 |. >MOV EAX,DWORD PTR DS:[404004]
004010A8 |. >MOV DWORD PTR SS:[ESP+4],EAX
004010AC |. >MOV EAX,DWORD PTR DS:[404000]
004010B1 |. >MOV DWORD PTR SS:[ESP],EAX
004010B4 |. >CALL GCCOllyT.00401AFC
004010B9 |. >MOV EBX,EAX ; |
004010BB |. >CALL <JMP.&msvcrt._cexit> ; |[msvcrt._cexit
004010C0 |. >MOV DWORD PTR SS:[ESP],EBX ; |
004010C3 |. >CALL <JMP.&KERNEL32.ExitProcess> ; \ExitProcess
004010C8 |> >MOV DWORD PTR DS:[402004],EAX ; |||
004010CD |. >MOV DWORD PTR SS:[ESP+4],EAX ; |||
004010D1 |. >MOV EBX,DWORD PTR DS:[<&msvcrt._iob>] ; |||msvcrt._iob
004010D7 |. >MOV EAX,DWORD PTR DS:[EBX+10] ; |||
004010DA |. >MOV DWORD PTR SS:[ESP],EAX ; |||
004010DD |. >CALL <JMP.&msvcrt._setmode> ; ||\_setmode
004010E2 |. >MOV EAX,DWORD PTR DS:[404018] ; ||
004010E7 |. >MOV DWORD PTR SS:[ESP+4],EAX ; ||
004010EB |. >MOV EAX,DWORD PTR DS:[EBX+30] ; ||
004010EE |. >MOV DWORD PTR SS:[ESP],EAX ; ||
004010F1 |. >CALL <JMP.&msvcrt._setmode> ; |\_setmode
004010F6 |. >MOV EAX,DWORD PTR DS:[404018] ; |
004010FB |. >MOV DWORD PTR SS:[ESP+4],EAX ; |
004010FF |. >MOV EAX,DWORD PTR DS:[EBX+50] ; |
00401102 |. >MOV DWORD PTR SS:[ESP],EAX ; |
00401105 |. >CALL <JMP.&msvcrt._setmode> ; \_setmode
0040110A \.^>JMP GCCOllyT.0040107E
Теперь мы знаем, что подпись для вызова main
занимает 3 аргумента, мы также знаем, что она будет называться до очистки и выхода из приложения, таким образом, мы получаем GCCOllyT.00401AFC
. Как видите, включение символов стоит дорого, это можно сделать в разделе дизассемблирования в меню параметров отладки.