I'm trying to make a simple debugger as my homework. The debugger does 3 steps.
- Read a exe file with
rb
flag, get its EntryPoint. - Call
CreateProcess
with flagCREATE_SUSPENDED | DEBUG_ONLY_THIS_PROCESS
, then set a breakpoint at EntryPoint - When debugee was stopped at EntryPoint. Read codes from EntryPoint.
Now my problem is, CreateProcess
returns true, but the following ReadProcessMemory
returns false and GetLastError
returns 299, AKA ERROR_PARTIAL_COPY
, so I can't set breakpoint at EntryPoint. I've search on Stack Overflow with keywords ERROR_PARTIAL_COPY
and ReadProcessMemory
and read some questions and answers, but those answers cannot solve my problem.
My approach comes here: Syringe, it is a 32-bit program, which runs well on my 64-bit PC.
Environment:
- Windows 10 20H2 (19042), 64-bit.
- CMake(generated by Visual Studio 2019, I didn't specify anything except linking zydis) generator: Visual Studio 2019, compiler: MSVC v142.
- Compiled with x86-debug mode
Here is my code snippet
auto* file = fopen("../debugee.exe", "rb");
IMAGE_DOS_HEADER dosHdr;
fread(&dosHdr, sizeof IMAGE_DOS_HEADER, 1, file);
fseek(file, dosHdr.e_lfanew, SEEK_SET);
IMAGE_NT_HEADERS ntHeaders;
fread(&ntHeaders, sizeof IMAGE_NT_HEADERS, 1, file);
auto IsWin32 = ntHeaders.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC;
std::cout << "parsing " << (IsWin32 ? "PE32" : "PE64") << " file\n";
auto imageBase = ntHeaders.OptionalHeader.ImageBase;
auto entry = ntHeaders.OptionalHeader.AddressOfEntryPoint + imageBase;
auto codeSize = ntHeaders.OptionalHeader.SizeOfCode;
STARTUPINFO startupInfo{sizeof STARTUPINFO};
PROCESS_INFORMATION pInfo;
auto r = CreateProcess(
"../debugee.exe", nullptr, nullptr, nullptr, false,
CREATE_SUSPENDED | DEBUG_ONLY_THIS_PROCESS,
nullptr, nullptr, &startupInfo, &pInfo);
printf("create process: %s, handle: %p\n", r ? "success" : "fail", pInfo.hProcess);
char buffer = 0;
char INT3 = 0xCC;
printf("address of buffer: %p\n", &buffer);
r = ReadProcessMemory(pInfo.hProcess, reinterpret_cast<void*>(entry), &buffer, 1, nullptr);
auto err = GetLastError();
printf("read: %s, error: %08X\n", r ? "success" : "fail", err);
r = WriteProcessMemory(pInfo.hProcess, reinterpret_cast<void*>(entry), &INT3, 1, nullptr);
err = GetLastError();
printf("patch: %s, error: %08X\n\n", r ? "success" : "fail", err);
ResumeThread(pInfo.hThread);
The output is
parsing PE32 file
create process: success, handle: 00000100
address of buffer: 00D3F5CF
read: fail, error: 0000012B
patch: fail, error: 000003E6 // WriteProcessMemory got another error ERROR_NOACCESS, I don't know if there are corelation, but I want to figure out why I got ERROR_PARTIAL_COPY first