Сейчас на форуме: hgdagon (+5 невидимых) |
eXeL@B —› Программирование —› Как правильно вызвать из чужой проги функцию из своей ДЛЛ |
. 1 . 2 . >> |
Посл.ответ | Сообщение |
|
Создано: 31 июля 2007 18:53 · Поправил: rmzvoid · Личное сообщение · #1 Начал осваивать увеличение функциональности программы, надо вобщем пропатчить несколько переменных и вставить пару хуков в прогу. Начал с простого, написал простую прогу: #include <stdio.h>
эту прогу и буду патчить затем написал ДЛЛ: // DLL.cpp : Defines the entry point for the DLL application.
прога падает. Кусок Проги дизасеблерованый: .text:00401000 _main proc near ; CODE XREF: start+13Ep
после пропатчивания кода моей ДЛЛ-кой: 00401000 mov eax,dword ptr ds:[00403010h]
до пропатчивания ИДА показывает что принтф находица тут: .rdata:00402050 printf dd ? ; DATA XREF: _main+18r откуда береца адрес 00812C68h и почему программа крешится, судя по дебагеру адрес 00812C68h указывает кудато далеко и совсем не в ту степь Дизасемблируя ДЛЛ посмотрел что адрес Hello() = 0x10001000 Пропатчивание переменных получается на ура, а вот call не могу |
|
Создано: 31 июля 2007 19:21 · Личное сообщение · #2 |
|
Создано: 31 июля 2007 19:27 · Личное сообщение · #3 |
|
Создано: 31 июля 2007 19:45 · Поправил: Executioner · Личное сообщение · #4 |
|
Создано: 31 июля 2007 19:48 · Поправил: Executioner · Личное сообщение · #5 |
|
Создано: 31 июля 2007 20:33 · Личное сообщение · #6 А это твое 00812C68h очень похоже на начало команды 68 2C810010 PUSH 1000812C с учетом того, что ImageBase твоей DLL, видимо, 0x10000000, ибо функцией memcpy((BYTE *)(0x0040101A), Hello, sizeof(DWORD)); ты копируешь по адресу 0x0040101A первые четыре байта функции Hello, насколько я понимаю. Хотя плохо знаю Си, могу ошибаться. ----- Уважайте других и пишите грамотно. |
|
Создано: 31 июля 2007 21:21 · Поправил: s0larian · Личное сообщение · #7 Executioner, точняк - ок копирует 4 байта из указателя а надо так:
но дело вот в чём - тебе надо пересчитать адрес и вбить его в инструкцию (структура примерно такая: [prefix] opcode operand). Глянь в интеловскую доку. Покажи байты твоего call-a - он может быть относительным и абсолютным. (самое простое, конечно, это mov eax, address; call eax" но для этого никогда нету места если патчишь одну инструкцию. С другой стороны, можешь забить любой набор инструкций в начало функции - твой hook запустится, и ты сможешь потом вызвать оригинал + смещение. (ессно надо вызвать не в середине инструкции и сохранить то что делали первые несколько оригинальных инструкций. |
|
Создано: 31 июля 2007 21:34 · Личное сообщение · #8 E8 cw CALL rel16 Call near, relative, displacement relative to next instruction. E8 cd CALL rel32 Call near, relative, displacement relative to next instruction. FF /2 CALL r/m16 Call near, absolute indirect, address given in r/m16. FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32. |
|
Создано: 31 июля 2007 21:56 · Личное сообщение · #9 s0larian пишет: ересчитать адрес Нафига? Ты ж сам выше привел FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32. У нас есть вызов вида call dword ptr ds:[00402050h]
Таким образом, если мы по адресу 00402050h запишем адрес нашей функции Hello, то будет вызываться именно она. ----- Уважайте других и пишите грамотно. |
|
Создано: 01 августа 2007 00:45 · Личное сообщение · #10 |
|
Создано: 01 августа 2007 03:18 · Личное сообщение · #11 |
|
Создано: 01 августа 2007 03:52 · Личное сообщение · #12 Сделал как писал s0larian unsigned int *p = (unsigned int *)0x0040101A;
теперь код после патча выглядит более как надо (вродебы), т.е. call вызывает по адресу по которому находится Hello 0x10001000: 00401018 FF 15 00 10 00 10 call dword ptr ds:[10001000h]
Но прога крашится всё равно с сообщением: Unhandled exception at 0x00206c68 in DLLPlug.exe: 0xC0000005: Access violation reading location 0x00206c68. 0x00206c68 это же кусок кода из Hello: 10001000 68 6C 20 00 10 push 1000206Ch
в чем теперь трабла? |
|
Создано: 01 августа 2007 03:59 · Личное сообщение · #13 |
|
Создано: 01 августа 2007 04:13 · Личное сообщение · #14 Кстати call ds:printf ссылается не на точку входа в процедуру а на какое-то непонятное (не парю в ассемблере дюже): .rdata:00402000 ; Section 2. (virtual address 00002000) .rdata:00402000 ; Virtual size : 0000031A ( 794.) .rdata:00402000 ; Section size in file : 00000400 ( 1024.) .rdata:00402000 ; Offset to raw data for section: 00000800 .rdata:00402000 ; Flags 40000040: Data Readable .rdata:00402000 ; Alignment : 16 bytes ? .rdata:00402000 ; .rdata:00402000 ; Imports from KERNEL32 .rdata:00402000 ; .rdata:00402000 ; ====================================================================== ===== .rdata:00402000 .rdata:00402000 ; Segment type: Pure data .rdata:00402000 ; Segment permissions: Read .rdata:00402000 _rdata segment para public 'DATA' use32 .rdata:00402000 assume cs:_rdata .rdata:00402000 ;org 402000h .rdata:00402000 ; HMODULE __stdcall GetModuleHandleA(LPCSTR lpModuleName) .rdata:00402000 GetModuleHandleA dd ? ; DATA XREF: start+Fr .rdata:00402004 dd 0 .rdata:00402008 ; .rdata:00402008 ; Imports from MSVCR71 .rdata:00402008 ; .rdata:00402008 ; void __cdecl exit(int) .rdata:00402008 _exit dd ? ; DATA XREF: start+180r .rdata:0040200C _XcptFilter dd ? ; DATA XREF: sub_4011BCr .rdata:00402010 _cexit dd ? ; DATA XREF: start:loc_40117Br .rdata:00402014 exit dd ? ; DATA XREF: start+151r .rdata:00402018 __p___initenv dd ? ; DATA XREF: start+12Ar .rdata:0040201C _amsg_exit dd ? ; DATA XREF: __amsg_exitr .rdata:00402020 __getmainargs dd ? ; DATA XREF: start+103r .rdata:00402024 _initterm dd ? ; DATA XREF: __inittermr .rdata:00402028 _c_exit dd ? ; DATA XREF: start:loc_4011AAr .rdata:0040202C _adjust_fdiv dd ? ; DATA XREF: start+9Dr .rdata:00402030 __p__commode dd ? ; DATA XREF: start+8Fr .rdata:00402034 __p__fmode dd ? ; DATA XREF: start+81r .rdata:00402038 __set_app_type dd ? ; DATA XREF: start+6Cr .rdata:0040203C _except_handler3 dd ? ; DATA XREF: .text:loc_4012F0r .rdata:00402040 __dllonexit dd ? ; DATA XREF: ___dllonexitr .rdata:00402044 ; _onexit_t __cdecl onexit(_onexit_t) .rdata:00402044 _onexit dd ? ; DATA XREF: __onexit+9r .rdata:00402048 _controlfp dd ? ; DATA XREF: __controlfpr .rdata:0040204C __setusermatherr dd ? ; DATA XREF: start+C0r .rdata:00402050 printf dd ? ; DATA XREF: _main+18r <--- сюда ссылается, а что это не знаю, у меня же после патча получается что call ds:0x10001000 ссылается на первую инструкцию функции Hello. Наскоко я думал и наскоко я не знаю ассемблера должны вызываться инструкции по 10001000h . Но чето не то, пойду книшку скачаю по ассемблеру |
|
Создано: 01 августа 2007 05:07 · Личное сообщение · #15 rmzvoid пишет: Сделал как писал s0larian unsigned int *p = (unsigned int *)0x0040101A; *p = (unsigned int)(unsigned int *)Hello; ты сделал не так. запутался с указателями. замени 0x0040101A на 0x00402050, если я правильно понимаю, что тебе надо. насчет dynamic и static не скажу, что будет проще. при dynamic - call будет вида FF 15, а при static - E8. если чувствуешь разницу между этими опкодами, должен понимать, в чем проблема. |
|
Создано: 01 августа 2007 05:11 · Личное сообщение · #16 |
|
Создано: 01 августа 2007 05:12 · Личное сообщение · #17 |
|
Создано: 01 августа 2007 05:25 · Личное сообщение · #18 sotona пишет: при dynamic - call будет вида FF 15, а при static - E8. если чувствуешь разницу между этими опкодами, должен понимать, в чем проблема. FF 15 50 20 40 00 у мя, но не понимаю до конца что такое 00402050 ) E8 это вроде что-то типа jmp (E9)? и к чему там приставка ds: знаю что дата сегмент, но не более ) Не думал что столько сложностей встречу |
|
Создано: 01 августа 2007 05:31 · Личное сообщение · #19 rmzvoid пишет: Не думал что столько сложностей встречу ну так прокатил или нет один из двух моих вариантов?! rmzvoid пишет: но не понимаю до конца что такое 00402050 0x00402050 - это адрес из таблицы импорта, часть которой ты нам привел выше. конкретно в 0x00402050 лежит адрес функции printf, а сама функция определена внутри DLL типа msvcrt*.dll |
|
Создано: 01 августа 2007 05:33 · Поправил: sotona · Личное сообщение · #20 |
|
Создано: 01 августа 2007 05:37 · Личное сообщение · #21 |
|
Создано: 01 августа 2007 05:39 · Личное сообщение · #22 |
|
Создано: 01 августа 2007 05:42 · Личное сообщение · #23 |
|
Создано: 01 августа 2007 05:43 · Личное сообщение · #24 |
|
Создано: 01 августа 2007 05:44 · Личное сообщение · #25 |
|
Создано: 01 августа 2007 05:55 · Поправил: sotona · Личное сообщение · #26 rmzvoid пишет: над чем посоветуете еще попрактиковать? )) чтобы приступить к встраиванию ДЛЛ в чужую прогу? не знаю... еще замечание - ты вначале использовал memcpy. может статься, что тебе нужно будет патчить не просто какие-то небольшие переменные, а достаточно большие куски кода или строки. поэтому неплохо бы, когда патчишь код(да и данные тоже), притормозить thread, в котором выполняется код, а после патча его вновь продолжить. за это отвечают SuspendThread, ResumeThread. список тредов можно получить по-разному, хотя бы средствами toolhelp api - Thread32First,Thread32Next. а еще ты работаешь с фиксированными адресами - константами типа 0x00402050. чтобы добиться некой универсальности, нужно освоить поиск кода по сигнатурам(типа "FF 15 ?? ?? ?? ??"), и уметь находить адрес нужной ячейки в таблице импорта, чтоб потом подменить её значение. вобщем, можно много чего придумать прикольного... в зависимости от того, какие задачи будут вставать |
|
Создано: 01 августа 2007 06:01 · Поправил: rmzvoid · Личное сообщение · #27 |
|
Создано: 01 августа 2007 06:32 · Поправил: sotona · Личное сообщение · #28 rmzvoid пишет: вспомнил - мне надо будет посреди кода чужой программы вызывать кусок своего кода из ДЛЛ, как это можно реализовать? т.е. как-то надо будет добавить пару команд между уже существующими 1) вставить jmp на свой код в нужное место. можешь E9 использовать, но тогда придется считать длину прыжка. лучший вариант: 68 XX XX XX XX C3, где вместо иксов адрес твоего кода. единственный недостаток - байтов приходится вставлять на один байт больше по сравнению с E9. 2) вставка перехода затрет одну-две команды, поэтому надо бы их где-то сохранить сначала, а потом выполнить. 3) ну и потом возврат из твоего кода. тоже джампом или еще как-нибудь. 4)важный момент - знаешь ли ты, между какими именно командами вставляешь код. потому что если неизвестна длина команды, которую затираешь, то придется использовать дизассемблер длин инструкций. готовые движки есть. еще можно как-нибудь поставить 0xCC(int3) заместо команды, а потом в VEH/SEH обработать исключение, выполняя свой код в обработчике. но лично мне этот вариант кажется сложнее и тормознее в выполнении. да и не совсем удовлетворяет требованиям. p.s. и еще, я поинтересуюсь - как заставляешь чужую прогу загрузить твою DLL ? |
|
Создано: 01 августа 2007 06:36 · Личное сообщение · #29 |
|
Создано: 01 августа 2007 07:03 · Поправил: rmzvoid · Личное сообщение · #30 |
. 1 . 2 . >> |
eXeL@B —› Программирование —› Как правильно вызвать из чужой проги функцию из своей ДЛЛ |