Несколько корректировок.
QUOTE(-=CHE@TER=- @ Jun 14 2018, 17:15)

5) Т.к. ты брезгуешь нормальными системами, то запускаешь Ольку от имени Администратора, плюс помни, что первый вылет в ней будет не на OEP, а где-то в дебрях системы, ибо Windows Vista и выше - гоумно. Так что делай сразу F9, чтобы оно до OEP дошло.
Это можно обойти, чтобы сразу на OEP вставало, если в опциях выбрать игнорировать последнее исключение (Debugging Options - Exceptions - Add last exception, не забыть галку на Ignore also following custom exception or ranges чтобы список работал).
QUOTE(-=CHE@TER=- @ Jun 21 2018, 20:03)

А ещё F8 на инструкции loop сразу пройдёт весь цикл, в то время как F7 будет переходить на начало при каждом шаге.
Спутал с отладчиком DOSBox. Во всяком случае в классической Ольке это не работает так.
QUOTE(-=CHE@TER=- @ Jun 21 2018, 20:03)

Если файл не изменялся, то при перезапуске бряки не будут пропадать, кроме случаев когда бряк стоит на памяти которая была динамически выделена или внутри .DLL.
x64dbg допилили, так что там бряки внутри .DLL не пропадают - удобно. Вроде бы, даже файл на диске изменять можно. Насчёт остального не проверял.
А ещё, рассказываю, как и обещал когда-то, одно ноу-хау, о том как можно быстро найти код распаковки/расшифровки чего-либо, если отлаживать с самого начала программу очень долго и муторно.
Чтение файлов в Windows, как правило, идёт через CreateFile + ReadFile. Исключение - когда файл мапится в память (тогда придётся перехватывать ещё mapping-функции и высчитывать адрес нужного блока памяти для смены прав). Поэтому можно поступить так:
1) Делаем wrapper-оболочку-прослойку между игрой и системной kernel32.dll:
game.exe -> kernelxx.dll -> kernel32.dll
2) В kernelxx перехватываем работу с CreateFile и сравниваем с именем файла, который нам нужен. Если наш - сохраняем дескриптор открытого файла.
3) В ReadFile смотрим какой файл читается - если нужный (сравнили с дескриптором), то ставим (после того как оригинальная функция отработала!) на весь буфер бряк программно - запрещаем обращение к этой памяти:
VirtualProtect(lpBuffer, nNumberOfBytesToRead, PAGE_NOACCESS, @tmp);
4) Теперь если где-то программа обратится к этому куску памяти, то отладчик сразу остановится на этом месте, т.к. выбьет ошибку. Можно вместо этого вызвать DebugBreak(); тогда в этом месте управление передастся отладчику и можно будет дальше смотреть кто и что с этим буфером делает (это если с ним сразу работают, а не через 10 минут после загрузки, когда понадобился).
5) Обращаю внимание, что изменить в отладчике права на обращения к памяти нельзя, а т.к. код распаковки будет постоянно это делать, то будут постоянно лезть ошибки - т.е. нашли адрес кода распаковки, bp <адрес> и перекомпилили библиотеку, чтобы больше запрета на обращение к памяти не было. Тут можно попробовать, наверное, PAGE_GUARD (см. документацию - оно как раз один раз срабатывает и возвращает старые права на память после этого), вместо PAGE_NOACCESS, но я уже не помню почему от PAGE_GUARD отказался (не срабатывало, вроде бы).
Вот пример такой библиотеки (я его слегка поменял и уменьшил, чтобы было нагляднее, но не тестировал, так что возможны ошибки в работе, хотя всё и компилируется без проблем под Delphi 7):
CODE
library KERNELXX;
uses Windows;
const
MyFileName = 'filename.ext';
var
MyHandle: THandle = INVALID_HANDLE_VALUE;
function CreateFileA(
lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: DWORD;
lpSecurityAttributes: PSecurityAttributes;
dwCreationDisposition, dwFlagsAndAttributes: DWORD;
hTemplateFile: THandle
): THandle; stdcall;
var s: ansistring;
begin
result:=Windows.CreateFileA(
lpFileName, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile
);
s:=lpFileName;
if (
(result <> INVALID_HANDLE_VALUE) and (Length(s) >= Length(MyFileName)) and
(Windows.lstrcmpiA(PAnsiChar(Copy(s, Length(s) - Length(MyFileName) + 1,
Length(MyFileName))), PAnsiChar(MyFileName)) = 0)
) then
begin
MyHandle:=result;
end;
end;
function ReadFile(hFile: THandle; Var Buffer; nNumberOfBytesToRead: DWORD;
var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
var
d: DWORD;
p: pointer;
begin
result:=Windows.ReadFile(
hFile, Buffer, nNumberOfBytesToRead,
lpNumberOfBytesRead, lpOverlapped
);
if (result = true) then
begin
if (hFile = MyHandle) then
begin
p:=@Buffer;
Windows.VirtualProtect(p, nNumberOfBytesToRead, PAGE_NOACCESS, @d);
// DebugBreak();
end;
end;
end;
function CloseHandle(hObject: THandle): BOOL; stdcall;
begin
result:=Windows.CloseHandle(hObject);
if (hObject = MyHandle) then MyHandle:=INVALID_HANDLE_VALUE;
end;
procedure RtlUnwind; stdcall; external 'kernel32.dll' name 'RtlUnwind';
exports
CreateFileA,
ReadFile,
CloseHandle,
SetFilePointer,
GetFileSize,
CreateDirectoryA,
GetCommandLineA,
RtlUnwind,
GetVersion;
end.
Обращаю внимание на несколько важных вещей связанных с этим кодом:
1) В exports должны быть все функции, которые экспортирует игра/программа, иначе она тупо не запустится.
2) Блок exports обязательно должен идти
после перехваченных функций, иначе перехватчики не будут работать (будет вызов оригинальных функций напрямую).
3) Если нужно вызвать оригинальный код из kernel32 (или другого юнита), то это нужно делать добавив имя такого юнита перед именем функции, как у объекта класса:
Windows.CreateFileA(...)
Потому что вызов:
CreateFileA(...)
создаст бесконечную рекурсию.
4) Ну и, конечно, не забудьте заменить в исполняемом файле игры/программы все строки "KERNEL32.DLL" на "KERNELXX.DLL", чтобы использовалась эта библиотека.
5) Можно не только работу с файлами перехватывать, но и работу с памятью, сетью, реестром (advapi32.dll - я обычно это делаю, чтобы при отладки игры мне в реестр не гадили) и так далее.
Мне идея такой библиотеки пришла в голову в 2015 году (обычные wrapper-то я ещё раньше делал - в старой версии патча для Турка) и безумно выручила - я как раз по заказу писал конвертер графики для какой-то игры (уже не помню точно для какой, но на сайте конвертер есть) и не мог никак до функции конвертирования добраться - в меню загружались обычные .BMP, а мне нужен был собственный формат игры, который только в игре загружался и только в определённый момент (когда этот объект был виден на экране). Там проблема, если правильно помню, была в том, что если ставить бряк на обращение к памяти (memory on access), то Олька почему-то начинает о-о-очень медленно работать, так что было практически невозможно дойти с момента загрузки до момента, когда нужный спрайт появлялся на экране (декодировался - шло обращение к памяти).