Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   Авторские статьи (https://forum.antichat.xyz/forumdisplay.php?f=31)
-   -   Расширение функциональности OllyDbg (https://forum.antichat.xyz/showthread.php?t=37547)

taha 09.04.2007 16:19

Расширение функциональности OllyDbg
 

Расширение функциональности OllyDbg

[ intro ]

Итак, начнём. Наверное каждый кто исследовал сложную/большую программу, сталкивался с проблемой запоминания адресов, подсчёта некоторых констант. Для сохранения адресов и коментариев к некоторым кускам кода, многие пользуються обычным Блокнотом (как и я). Что ни говори, без него уже никуда. Тут возникает проблема его вызова. Как то лень постоянно открывать Пуск > etc. Многие возразят: ‘А разве, Win+R > notepad, не достаточно быстро?’. Да это быстро/удобно, но всё равно не совсем то. Хорошо бы создать дополнительное меню “tools” в OllyDbg, где бы и находились итемы часто используемых прог. Блокнот, Калькулятор etc. Но без хирургического вмешательства этого не достичь. Придется OllyDbg “лечь под нож”.

На данную статью меня вдохновила статья из второго номера журнала ARTeam и отсутсвие подобных на великом и могучем.

[ tools ]

Для этого нам понадобятся:
Restorator 2005 – редактор ресурсов
Shadow - я выбрал эту модификацию OllyDbg (по вкусу)
MASM – компилятор

[Правка ресурсов]

Windows-программа, помимо исполняемого кода, содержит ресурсы: иконки, диалоги, битмапы, музыку. Только ресурсы не преобразовываются как исполняемый код. И для исправления ресурсов намного удобнее использовать специальные программы. Для этого я выбрал Restorator.

Открываем Shadow.exe в Restorator 2005. Перед нами папки ресурсов: диалоги, картинки, меню. Нам естественно нужна папка Menu. Заходим в неё. Выбираем MAINMENU.


Я решил засунуть “tools” между “Options”и “Windows”. Поэтому пишем следующее:

Код:

POPUP "&Tools"
 {
  MENUITEM "&Calc", 4001
  MENUITEM "&Notepad", 4002
 }

Естественно между POPUP "Op&tions" {…} и POPUP "&Window" {…}.

4001d – 0FA1h – это ID пункта, будет отсылаться вместе с сообщением. Именно этот ID даёт программе понять, что от неё хотят (точнее понять какой пункт выбран).

Теперь закрываем редактор, попутно разрешая сохранить изменеия и бэкап.
Открываем Shadow.exe !


Так... Меню создали. Теперь нужно сделать так, чтобы OllyDbg обрабатывала сообщения этих итемов.

[Цикл сообщений]

Когда пользователь выбирает пункт меню, Windows отсылает программе сообщение WM_COMMAND, которое обрабатывается в цикле сообщений. Каждый, кто программировал под Windows, писал следующие строки:

Код:

.WHILE TRUE
  invoke GetMessage, ADDR msg,NULL,0,0
 .BREAK
 .IF (!eax)
  invoke TranslateMessage, ADDR msg
  invoke DispatchMessage, ADDR msg
.ENDW

GetMessage пеpедает указатель на MSG стpуктуpу Windows. Эта стpуктуpа будет заполнена инфоpмацией о сообщении, котоpые Winsows хотят послать окну этого модуля. Если возвращается false, то это сигнал, что пора завершаться. TranslateMessage переводит код нажатой клавиши в ASCII-сомвол. И теперь самое интересное – DispatchMessage. Эта API передаёт управление функции обработки сообщений (WndProc). Тоесть эта функция поможет нам найти “WndProc”, в которой содержится обработчик сообщения WM_COMMAND.

Итак отрываем файл Shadow.exe в другой Olly[Dbg|ICE|Shadow]. Мы попадём на EP.

Код:

00401000 > $ /EB 10    JMP SHORT Shadow.00401012
00401002    |66      DB 66                                    ;  CHAR 'f'
00401003    |62      DB 62                                    ;  CHAR 'b'
00401004    |3A      DB 3A                                    ;  CHAR ':'
00401005    |43      DB 43                                    ;  CHAR 'C'
00401006    |2B      DB 2B                                    ;  CHAR '+'

Запускаем программу (F9) и закрываем все лишнии окна (такие как CPU, хэндлеры, логи, карта памяти), в отлаживаемой программе. Оставивь нужно только основное окно. Мы ведь не хотим рыться в сообщениях чужих окон. Теперь перейдём в DispatchMessage. Для этого жмём Ctrl-G и вводим “DispatchMessageA”. Ставим break “F2” в начале функции и запускаем программу. Останавливаемся. Снимаем бряк. Переходим на карту памяти Alt-M и ставим break на секцию кода. Теперь вам понятна логика действий? Сейчас мы внутри DispatchMessage, которая передаёт управление “WndProc”. Соответсвенно первое попадание в секцию кода – это попадание на “WndProc”. F9 и мы попадём сюда:

Код:

004323D4  /$  55                                PUSH EBP
004323D5  |.  8BEC                              MOV EBP,ESP
004323D7  |.  81C4 04F0FFFF                    ADD ESP,-0FFC
004323DD  |.  50                                PUSH EAX
004323DE  |.  81C4 30FDFFFF                    ADD ESP,-2D0
004323E4  |.  53                                PUSH EBX
004323E5  |.  56                                PUSH ESI
004323E6  |.  57                                PUSH EDI
004323E7  |.  8B5D 10                          MOV EBX,[ARG.3]
004323EA  |.  8B45 0C                          MOV EAX,[ARG.2]
004323ED  |.  3D 11010000                      CMP EAX,111                              ;  Switch (cases 1..478)
004323F2  |.  7F 61                            JG SHORT Shadow.00432455
004323F4  |.  0F84 1E140000                    JE Shadow.00433818

И вот уже невооружонным глазом видно где проверка WM_COMMAND.

004323ED |. CMP EAX,111 ; Switch (cases 1..478)

WM_COMMAND equ 111h

Идём по F8 до строки по адресу 004323ED. Далее в меню выбираем “Go to”.


Дальше, естественно, “Case 111 (WM_COMMAND)”. И мы здесь:

Код:

00433818  |> \8BCB                              MOV ECX,EBX                              ;  Case 111 (WM_COMMAND) of switch 004323ED
0043381A  |.  C1E9 10                          SHR ECX,10
0043381D  |.  66:85C9                          TEST CX,CX
00433820  |.  0F85 EC090000                    JNZ Shadow.00434212
00433826  |.  8BC3                              MOV EAX,EBX

Помещаем сюда бряк и выбираем, добавленный нами, пункт в “tools”. Например “calc”. Идём по F8 вот до этого места:

Код:

00433A1A  |. /E9 77070000                      JMP Shadow.00434196
00433A1F  |> |81EA C7090000                    SUB EDX,9C7
00433A25  |. |0F84 37070000                    JE Shadow.00434162
00433A2B  |. |4A                                DEC EDX
00433A2C  |. |0F84 4E070000                    JE Shadow.00434180
00433A32  |. |E9 5F070000                      JMP Shadow.00434196
00433A37  |> |33C0                              XOR EAX,EAX                              ;  Case 7D1 of switch 0043382F
00433A39  |. |83C9 FF                          OR ECX,FFFFFFFF

JMP Shadow.00434196 – это переход в случаее если обработка полученного сообщения не предусмотренно.

Теперь нам следует подыскать свободное место в программе (для внедрения некоторого кода). Как всегда место нашлось в оверлее.

Код:

004AF670      00                                DB 00
004AF671      00                                DB 00
004AF672      00                                DB 00
004AF673      00                                DB 00
004AF674      00                                DB 00
004AF675      00                                DB 00
004AF676      00                                DB 00
004AF677      00                                DB 00
004AF678      00                                DB 00
004AF679      00                                DB 00
004AF67A      00                                DB 00
004AF67B      00                                DB 00
004AF67C      00                                DB 00
004AF67D      00                                DB 00
004AF67E      00                                DB 00

И что же мы туда будем внедрять? Нет! Не обработку данного сообщения, хотя это частично так. Это было бы слишком жирно. Мы напишем dll, Функцию из которой, будем вызывать с этого участка.

Код:

004AF670  > \60                                PUSHAD
004AF671  .  68 97EC5000                      PUSH Shadow_-.0050EC97                  ; /ProcNameOrOrdinal = "f_menu"
004AF676  .  68 8DEC5000                      PUSH Shadow_-.0050EC8D                  ; |/FileName = "tools.dll"
004AF67B  .  E8 B8FAFFFF                      CALL <JMP.&KERNEL32.LoadLibraryA>        ; |\LoadLibraryA
004AF680  .  50                                PUSH EAX                                ; |hModule
004AF681  .  E8 0AFAFFFF                      CALL <JMP.&KERNEL32.GetProcAddress>      ; \GetProcAddress
004AF686  .  FFD0                              CALL EAX
004AF688  .  61                                POPAD

Теперь JMP Shadow.00434196 меняем на JMP Shadow.004AF670, а в конец этого кода добавляем

Код:

004AF689  .^ E9 084BF8FF                      JMP Shadow_-.00434196
Отлично! Так же не забудьте записать где-нибудь имена библиотеки и функции.

Заметка:
-------------------------------
CALL <JMP.&KERNEL32.LoadLibraryA> и CALL <JMP.&KERNEL32.GetProcAddress> - не тупо вбиты как “call LoadLibraryA”, “call GetProcAddress”. А как “CALL 004AF138”, “CALL 004AF090”.

Код:

004AF138  $- FF25 B4D35000                    JMP DWORD PTR DS:[<&KERNEL32.LoadLibrary>;  kernel32.LoadLibraryA

004AF090  $- FF25 44D35000                    JMP DWORD PTR DS:[<&KERNEL32.GetProcAddr>;  kernel32.GetProcAddress

Это сделанно для того, чтобы файл мог запускаться на других системах, где адресс API может быть другим.
--------------------------------

Теперь сохраним пропатченный файл. Для этого в меню выбираем “Copy to executable” > “All modifications” > “Copy all”. В открывшемся окне выбираем “Save file” и сохраняем.

[Пишем dll]

Начнём со скелета DLL.

Код:

.386
.model flat, stdcall
option casemap:none

include D:\masm32\include\windows.inc
include D:\masm32\include\user32.inc
include D:\masm32\include\kernel32.inc
includelib D:\masm32\lib\user32.lib
includelib D:\masm32\lib\kernel32.lib

.code

DLLEntry proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
       
        .if reason == DLL_PROCESS_ATTACH
                mov eax,TRUE
        .endif                                                                       
        Ret
       
DLLEntry Endp

f_menu proc
 RET
f_menu EndP

end DLLEntry

Теперь о том как получить сообщение. Когда шли по F8, думаю вы заметили, что оно храниться в edx. Но когда выполняются LoadLibraryA, GetProcAddress регистр edx засерается. Не забываейте, что мы сохранили в стеке все регистры, командой PUSHAD. PUSHAD заносит в стек все регистры от eax до edi


Соответсвенно ESP+14h – это содержимое edx. Только когда управление попадёт в нашу функцию, в стек войдёт ещё и адрес возврата. Тогда edx будет по ESP+18h.


В итоге у меня получился следующий файл

Код:

.386
.model flat, stdcall
option casemap:none

include D:\masm32\include\windows.inc
include D:\masm32\include\user32.inc
include D:\masm32\include\kernel32.inc
includelib D:\masm32\lib\user32.lib
includelib D:\masm32\lib\kernel32.lib

.data
        p_calc                db "\calc.exe",0
        p_notepad        db "\notepad.exe",0

.data?
        pi                        PROCESS_INFORMATION                        <>
        startinfo        STARTUPINFO                                        <>
        buffer db 50 dup(?)

.code

DLLEntry proc hInstDLL:DWORD, reason:DWORD, unused:DWORD
       
        .if reason == DLL_PROCESS_ATTACH
                mov eax,TRUE
        .endif                                                                       
        Ret
       
DLLEntry Endp

f_menu proc
 mov eax,[esp+18h]
 cmp eax,5D9h
 jne @F
 invoke GetSystemDirectory, addr buffer, sizeof buffer
 invoke lstrcat,addr buffer,addr p_calc
 invoke CreateProcess, addr buffer, NULL, NULL, NULL,\
                      FALSE, NORMAL_PRIORITY_CLASS,\
                      NULL, NULL, addr startinfo, addr pi
 RET
@@:
 cmp eax,5DAh
 jne @F
 invoke GetWindowsDirectory, addr buffer, sizeof buffer
 invoke lstrcat,addr buffer,addr p_notepad
 invoke CreateProcess, addr buffer, NULL, NULL, NULL,\
                      FALSE, NORMAL_PRIORITY_CLASS,\
                      NULL, NULL, addr startinfo, addr pi
@@:
 RET
f_menu EndP

end DLLEntry

Компилим! Запускаем нашу Shadow.exe. Выбираем пункт и... Всё работает! Теперь блокнот\калькулятор можно вызвать из меню.

[Заключение]

Теперь можно смело расширять возможности любой проги. Менять настройки под себя.


Удобно! +)

PS. Нужно будет добавить кнопку соединения с инт0рнетом))))

ProTeuS 09.04.2007 21:54

хороший пример эксплуатации идеи дероко, респект )
ЗЫ: если преследовать именно идею записи адрессов и констант, то есть ку4а плагинов (нопремер оллипад) ;)

hidden 09.04.2007 22:03

Отлично, многим будет познавательно, вот только LoadLibraryA и GetProcAddress, лучше не вставлять в основной цикл окна, это замедлит обработку сообщений, в данном случае от меню, так как они выполняются не так уж и быстро, их лучше вызвать при старте, и сохранить куда нибудь этот адрес функции или в крайнем случае сделать проверку, есть ли у нас уже этот адрес и если нет тогда выполнить.

taha 09.04.2007 23:17

OllyPad - это круто, но не очень. Пусть афтар дорабатывает. Блокнот всётаки пока удобней. Хотя если нужно сделать чтот побыстрому, то OllyPad самое то.

LoadLibraryA и GetProcAddress - несуть. Это так.. пробный вариант.. Когда сделал, было лень что то менять))

EB_FE 21.06.2008 00:19

taha
ну тут можно и не попасть на обработку wm_command. Например,
в win2000 все будет хорошо, а в winXP я попадаю на код
7E3689F1 > 8BFF MOV EDI,EDI

Так что тут лучше юзать бряк на DefWindowProcA. (Хотя и не самый лучший вариант).
А вот как найти "переход в случаее если обработка полученного сообщения не предусмотренно" - это я не смог. можешь подсказать как искать это переход?


Время: 22:55