逆向 | 双进程保护模板
继续补充书中的代码:
#include <stdio.h>
#include <Windows.h>
#define _PEB void
int FatherProcessMain();
int ChildProcessMain(); // 提前声明函数
int main(){
_PEB* pPEB = 0;
_asm{
mov eax, dword ptr fs:[0x18];
mov eax, dword ptr [eax+0x30];
mov pPEB, eax;
};
BYTE BeingDebugged = (BYTE)(*((BYTE*)pPEB + 0x02));
// 对这里有疑问的小伙伴可以参见7.2.1节中的内容
if(!BeingDebugged) // 如果没有被调试,则调用父进程函数
{
return FatherProcessMain();
}
return ChildProcessMain(); // 如果被调试,则调用子进程函数
}
int FatherProcessMain(){
unsigned char shellcode[] =
{ 0x66,0xb8,0xdf,0xb0,0xdf,0x73,0x60,0x65,0x64,0xbe,
0x4e,0xf3,0x8a,0x23,0x33,0x33,0x33,0x8b,0xff,0xff,
0xff,0xff,0xc0,0x98,0x5b,0xe7,0x53,0x71,0x33,0xdb,
0x1d,0x32,0x33,0x33,0xb0,0xf7,0x37,0x6c,0x6d,0x68,
0xb0,0xf7,0x73,0x8,0xdf,0xdb,0xed,0x33,0x33,0x33,
0xb8,0xd6,0x6e,0xf0
};
printf("I am Father \n");
char filename[MAX_PATH];
GetModuleFileName(0, filename, MAX_PATH); // 获取自身文件名
STARTUPINFO si={0};
GetStartupInfo(&si);
PROCESS_INFORMATION pi={0};
printf("path: %s \n", filename);
// 以调试模式创建子进程
if(!CreateProcess(filename,NULL,NULL,NULL,FALSE,DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&si,&pi)) //创建被调试进程
{
printf("fail to create subprocess! \n");
return 0;
}
printf("[f] subprocess id: %d \n", pi.dwProcessId);
BOOL WhileDoFlag=TRUE;
DEBUG_EVENT DBEvent ;
DWORD dwState;
while (WhileDoFlag)
{
WaitForDebugEvent(&DBEvent, INFINITE); // 等待调试事件
dwState = DBG_EXCEPTION_NOT_HANDLED;
switch(DBEvent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT: // 子进程创建
dwState = DBG_CONTINUE;
break;
case EXIT_PROCESS_DEBUG_EVENT: // 子进程退出
WhileDoFlag = FALSE;
break;
case EXCEPTION_DEBUG_EVENT:
switch (DBEvent.u.Exception.ExceptionRecord.ExceptionCode) // 获取异常编号
{
case EXCEPTION_BREAKPOINT:
{
CONTEXT Regs = {0};
Regs.ContextFlags = CONTEXT_FULL; // 获取全部的上下文
DWORD ret = GetThreadContext(pi.hThread, &Regs);
if (Regs.Eip == 0x4016b6){ // 子进程人工抛出的断点
printf("[f]: 接收到预定中断,不处理 \n");
dwState = DBG_CONTINUE; // 忽略,继续运行
// dwState = DBG_EXCEPTION_NOT_HANDLED; // 执行except handle
}else{
printf("[f]: 接收到int3中断 from %x \n", Regs.Eip);
dwState = DBG_CONTINUE;
}
break;
}
case EXCEPTION_INT_DIVIDE_BY_ZERO:
{
CONTEXT Regs = {0};
Regs.ContextFlags = CONTEXT_FULL; // 获取全部的上下文
DWORD ret = GetThreadContext(pi.hThread, &Regs);
printf("[f]: 接收到divided by zero from %x \n", Regs.Eip);
// 使用smc的方式修改子进程空间内容
for (int i = 0; i < sizeof(shellcode); i ++){
shellcode[i] ^= 0x33;
}
VOID* p_smccode = (VOID*)0x00401660u; // 这里通过调试确定位置
DWORD flOldProtect;
VirtualProtectEx(pi.hProcess, p_smccode, sizeof(shellcode), PAGE_EXECUTE_READWRITE,&flOldProtect);
BOOL bRet = WriteProcessMemory(pi.hProcess, p_smccode, shellcode, sizeof(shellcode), NULL);
if (!bRet){
printf("[f] WriteProcessMemory err! \n");
}
// 调整下一步的eip
Regs.Eip += 2; // 跳过2字节的除0操作
SetThreadContext(pi.hThread, &Regs);
dwState = DBG_CONTINUE; // 继续运行
break;
}
}
break;
}
ContinueDebugEvent(pi.dwProcessId, pi.dwThreadId, dwState); // 继续执行子进程的线程
}
CloseHandle(pi.hProcess); // 关闭相应的句柄
CloseHandle(pi.hThread);
return 0;
}
// 代码长度54字节, 编译完成后手动删除这个函数中的字节码
void smc_code(){
printf("[win] you reach the real path of child process! \n");
}
int ChildProcessMain(){
printf("I am Child. \n");
int a = 1;
__try{
__asm{
int 3; // 软中断
}
a = a / 0; // 触发父进程smc
smc_code();
}
__except(1)
{
printf("child err. \n");
exit(-1); // 调试器不处理异常,说明程序没有正常运行,直接退出
}
printf("child over. \n");
return 0;
}
标签:逆向,int,Regs,dwState,0x33,printf,进程,pi,模板
From: https://www.cnblogs.com/Mz1-rc/p/18509116