我用C来按罗云斌书上的代码重写,调试其书上的提的Test.exe
当现在为CREATE_PROCESS_DEBUG_EVENT时,则写入INT 3中断,
但在WriteProcessMemory无法把其写入,查看其ErrorCode为0x12b
ERROR_PARTIAL_COPY
我在 WriteProcessMemory前加上
VirtualProtectEx(ProcessInfo.hProcess, pBreak_point1, 1, PAGE_READWRITE, PAGE_READONLY);
也不行
而且VirtualProtectEx也返回了0。
请问是什么原因呢?要怎样才能写入INT 3?
下面列出代码
#include<windows.h>
#include<process.h>
#include "resource.h"
PROCESS_INFORMATION ProcessInfo;//进程信息结构
STARTUPINFO startupInfo;//指定新进程的主窗口特性结构
DEBUG_EVENT debugEvent;//调试事件结构
//汇编中要加上align dword将它定义为双字对齐
CONTEXT context;//存储的是寄存器状态,参考老罗P489
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
BOOL processSuccess, processWrite, processChange;
//WORD infoBuffer;
DWORD patch = 0x9090;
DWORD oldByte = 0x60;//入口处的原数据
DWORD int3 = 0xCC; //int 3中断
DWORD lastErrorCode;
DWORD patch_position = 0x00401004;//被修改的地址
DWORD break_point1 = 0x00405120;//第一个断点
DWORD break_point2 = 0x00401000;//第二个断点
LPVOID pBreak_point1 = (LPVOID)break_point1;
LPVOID pBreak_point2 = (LPVOID)break_point2;
LPVOID pInt3 = (LPVOID)int3;
LPVOID pOldByte = (LPVOID)oldByte;
LPVOID pPatch_position = (LPVOID)patch_position;
LPVOID pPatch = (LPVOID)patch;
GetStartupInfo(&startupInfo);//返回进程在启动时被指定的 STARTUPINFO 结构
//创建新进程和它的主线程,成功返回非零值
processSuccess = CreateProcess("Test.exe", NULL, NULL, NULL, 0, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS,
NULL, NULL, &startupInfo, &ProcessInfo);
if(!processSuccess)
{
MessageBox(NULL, TEXT("无法装载文件!"), NULL, MB_OK | MB_ICONSTOP);
ExitProcess(0);
}
//调试进程
while(TRUE)
{
WaitForDebugEvent(&debugEvent, INFINITE);//获取调试事件
if(debugEvent.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
{//事件代码为进程退出则退出循环
break;
}
//如果进程开始,则将入口地址处的代码改为 int 3 断点中断
if(debugEvent.dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT)
{//写入INT 3中断机器码,使程序异常中断
processChange = VirtualProtectEx(ProcessInfo.hProcess, pBreak_point1, 1, PAGE_READWRITE, PAGE_READONLY);
processWrite = WriteProcessMemory(ProcessInfo.hProcess, pBreak_point1, pInt3, 1, NULL);
lastErrorCode = GetLastError();//0x12b ERROR_PARTIAL_COPY
//Only part of a ReadProcessMemory or WriteProcessMemory request was completed.
}
else if(debugEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
{//如果发生断点中断,则恢复断点处代码并设置单步中断
if(debugEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT)
{
context.ContextFlags = CONTEXT_FULL;//访问全部寄存器
GetThreadContext(ProcessInfo.hThread, &context);//把当前目标线程的环境返回CONTEXT结构,即取得当前寄存器值
if(context.Eip == break_point1 + 1)
{
context.Eip -= 1;//如EIP指针已移到断点下句则返回断点处
WriteProcessMemory(ProcessInfo.hProcess, pBreak_point1, pOldByte, 1, NULL);//恢复断点处原来的指令
context.EFlags |= 0x100;//将单步标志置一,以后每执行一条指令会发生单步中断回到调试器中
SetThreadContext(ProcessInfo.hThread, &context);//将线程环境设置回去
}
}
else if(debugEvent.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)//单步调试
{
//如果单步中断到了指定位置,则进行内存补丁
context.ContextFlags = CONTEXT_FULL;//访问全部寄存器
GetThreadContext(ProcessInfo.hThread, &context);//把当前目标线程的环境返回CONTEXT结构,即取得当前寄存器值
if(context.Eip == break_point2)
{//找到程序入口处,进行补丁
WriteProcessMemory(ProcessInfo.hProcess, pPatch_position, &pPatch, sizeof(patch), NULL);
break;
}
else
{
context.EFlags |= 0x100;//将单步标志置一,以后每执行一条指令会发生单步中断回到调试器中
SetThreadContext(ProcessInfo.hThread, &context);//将线程环境设置回去
}
}
}
ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);//恢复被调试进程的运行,此两ID为发生调试事件的进程线程ID
}
CloseHandle(ProcessInfo.hProcess);//关闭进程句柄
CloseHandle(ProcessInfo.hThread);//关闭线程句柄
ExitProcess(0);
}
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!