Пытаюсь записать в память процесса данные, VirtualProtectEx и WriteProcessMemory проходят успешно, но данные не изменяются. При попытке записать в данный адрес 1024 байта, записываются только последние ~300 байт, первые же ~700 остаются неизменными. Причем при записи по другим адресам таких проблем нет. Единственное отличие этого адреса, то, что он располагается в сегменте rdata, а те, куда запись проходит успешно text и data. Что самое интересное, если считать по этому адресу данные с помощью ReadProcessMemory, то считывается то, что записали, а если я смотрю этот участок памяти с помощью ollydbg, то данные там не изменяются. Есть ли какие то ограничения по записи в rdata, и если есть, возможно ли их обойти? Или в чем же может быть дело? Возможно, будет полезна дополнительная информация - процесс запускаю сам в состоянии CREATE_SUSPENDED, произвожу необходимые изменения с помощью VirtualProtectEx/WriteProcessMemory после чего делаю ResumeThread. Запись происходит так: Код (Text): if VirtualProtectEx(hProcess, ptr, 1024, PAGE_READWRITE, oldProtect) then begin //ReadProcessMemory(hProcess, ptr, patch, len, writtenBytes); res := WriteProcessMemory(hProcess, ptr, patch, len, writtenBytes); if not res then WriteToLog(lhSystemLog, Format('WriteProcessMemory fail: %s', [SysErrorMessage(GetLastError)])); result := res and (len=Integer(writtenBytes)); // восстанавливаем права обратно VirtualProtectEx(hProcess, ptr, 1024, oldProtect, oldProtect); end else WriteToLog(lhSystemLog, Format('VirtualProtectEx fail: %s', [SysErrorMessage(GetLastError)]));
не думаю, тк я подменяю адрес импортируемой функции, а программа продолжает использовать оригинальный адрес функции.
да один, такой процесс в системе, на момент отладки один. и другие изменения в olly отлично видны. вот картинка до патча и после. выглядит очень странно. данные писались с адреса 4E7000 в количестве 10к байт. В начале картина аналогичная, местами видны тестовые данные AE. А с адреса 4E7384 и до 4E9800 уже идут только тестовые данные, без вкрапления оригинальных.
1024 байта? всю таблицу импорта подменяете штоль?) может сам ваш процесс ее и переписывает))) вообще и то и то - отображения файла на виртуальную память... можете посмотреть права и флаги страниц... сделайте VirtualQuery страницам, куда замаппирована .rdata и куда замаппирована .text например (State, Type и AllocationProtect)...
Может софтина восстанавливает то что вы меняете из какого-нибудь своего потока. Аппаратный бряк в Olly нужную область памяти можно попробовать и посмотреть, кто и как пишет в память.
1024 в VirtualProtectEx стоит заменить на len, но тк все патчи точечные (менее 16 байт) то 1024 хватает. Что касается 10к байт, то это тестов ради. Реально в таблице импорта надо заменить только 4 байта. Я тоже только сейчас заметил, что заменены нулевые dword'ы, но после адреса 4E7384 заменены уже не только нулевые. И напомню еще раз, что ReadProcessMemory считывает по всем адресам, то что было записано. Сегодня уже не посмотрю, какие флаги/права на страницах, но завтра обязательно отпишусь. Программа не может ничего восстановить, тк в момент применения патчей процесс в состоянии SUSPENDED
CFA Вы пытаетесь изменить таблицу импортируемых функций, когда она еще не "инициализирована" (да простят меня Гуру за вольность трактовки) - "инициализация" происходит после запуска вами потока (ResumeThread). И не забывайте, что таблиц - две копии. Вы не видите это в оле, т.к. аттач происходит к уже запущенному процессу - при этом "инициализация" таблиц импорта уже произошла. Возьмите любой memviewer и посмотрте интересующую память после патча, но ДО запуска потока и сравните ее с тем, что будет ПОСЛЕ запуска потока.
Кое что проясняется. Был бы благодарен, за ссылку про "две копии таблицы импорта". И если я правильно понял, то у меня не получится сделать задуманное - подменить в таблице импорта адрес функции и таким образом перехватить ее? И задачу надо как то решать по другому?
gorodon Верно. Импорт настраивается при инициализации процесса в LdrpInitializeProcess() -> LdrpWalkImportDescriptor() после подгрузки Kernel32.dll. Отладчик создаёт потоки в процессе, именно этот поток и выполняет инициализацию.
Да, что за две таблицы импорта?? Вам легче подгрузить длл-ку, которая поставит хуки. Создаете процесс суспендед -> выделяете память->пишите в нее стаб который грузит длл-ку-> вставляете um APC на этот стаб. Она вызовется когда все будет проинициализировано и все будет ок. Таким образом вам надо написать только 1 стаб, вместо n (кол-во хукаемых ф-ций). Но придется таскать с собой длл-ку Если подумать, то можно сделать даже без стаба
onSide Используются две IAT(IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk и FirstThunk), изменяется одна.