这个Loader要干的事有:
1.启动目标程序.
2.读取/修改目标程序的内存 或 寄存器
用到的Debug Api有:
CreateProcess —— 用于创建被调试进程
WaitForDebugEvent —— Debug Loop(调试循环)的主要构成函数
ContinueDebugEvent —— 用于构成Debug Loop
GetThreadContext —— 得到被调试进程的寄存器信息
SetThreadContext —— 设置被调试进程的寄存器信息
ReadProcessMemory —— 得到被调试进程的内存内容
WriteProcessMemory —— 设置被调试进程的内存内容
相应的数据结构如下
CONTEXT —— 寄存器结构
STARTUPINFO —— Start信息
PROCESS_INFORMATION —— 进程相关信息
DEBUG_EVENT —— Debug Event(调试事件)结构
Loader具体代码如下:
//
MemoryReader.cpp : 定义控制台应用程序的入口点。
// AntiDebug:IsDebugPresent如何避开?
// 加壳处理不完善
//
#include " stdafx.h "
#include " windows.h "
#include " Commdlg.h "
#include " winnt.h "
BYTE INT3 = 0xCC ;
// 写入前的
BYTE Old;
// 页面属性
DWORD OldProtect;
// 是否已写入INT3
bool HasINT3 = false ;
bool IsFirstINT3 = true ;
DWORD BreakPoint = 0x00452191 ;
BYTE Org[ 8 ] = { 0xE8 , 0x4E };
// 判断是否解压完成
bool IsUnpacked(PROCESS_INFORMATION pi)
{
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
printf( " Exe Info:Eax:%x,Esp:%x,Eip:%x\n " ,context.Eax,context.Esp,context.Eip);
ResumeThread(pi.hThread);
BYTE mem[ 8 ];
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
ReadProcessMemory(pi.hProcess,(LPCVOID)BreakPoint, & mem, 8 ,NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
printf( " hex num is:%x,%x,%x,%x\n " ,mem[ 0 ],mem[ 1 ],mem[ 2 ],mem[ 3 ]);
if (mem[ 0 ] ^ 0xff == Org[ 0 ] && mem[ 1 ] ^ 0xff == Org[ 1 ])
{
// 不能乱调用
Old = mem[ 0 ];
return TRUE;
}
return false ;
}
// 写INT3
bool WriteINT3(PROCESS_INFORMATION pi)
{
// VirtualAllocEx(pi.hProcess,(LPVOID)0x0101259b,sizeof(INT3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
SuspendThread(pi.hThread);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & INT3, sizeof (INT3),NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
HasINT3 = ret;
ResumeThread(pi.hThread);
return ret;
}
// 改回去
bool CleanINT3(PROCESS_INFORMATION pi)
{
// SuspendThread(pi.hThread);
bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & Old, sizeof (Old),NULL);
if (ret == false )
{
printf( " 改回去失败!\n " );
}
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
context.Eip -- ;
SetThreadContext(pi.hThread, & context);
printf( " 已经改回去了,Eax:%x\n " ,context.Eax);
return ret;
}
// 隐藏Debug
void HideDebug(PROCESS_INFORMATION pi)
{
BYTE ISDEBUGFLAG = 0x00 ;
int ISHEAPFLAG = 2 ;
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
// IsDebugPresent_Flag
WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x2 ), & ISDEBUGFLAG, 1 ,NULL);
// NTGlobal_Flag 用0D则为70 这个为0 防止其他调试器存在
WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x68 ), & ISDEBUGFLAG, 1 ,NULL);
// GetProcessHeap_Flag
DWORD HeapAddress;
ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx + 0x18 ), & HeapAddress, sizeof (HeapAddress),NULL);
WriteProcessMemory(pi.hProcess,(LPVOID)HeapAddress, & ISHEAPFLAG, sizeof (ISHEAPFLAG),NULL);
ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx + 0x68 ), & ISDEBUGFLAG, 1 ,NULL);
printf( " NT_GLOBAL=%d\n " ,ISDEBUGFLAG);
ResumeThread(pi.hThread);
}
int main( int argc, char * argv[])
{
char f_name[ 256 ];
f_name[ 0 ] = NULL;
OPENFILENAME filename;
ZeroMemory( & filename, sizeof (OPENFILENAME));
filename.lStructSize = sizeof (OPENFILENAME);
filename.hwndOwner = NULL;
filename.lpstrFilter = " *.exe " ;
filename.lpstrFile = f_name;
filename.nMaxFile = 256 ;
filename.lpstrInitialDir = NULL;
filename.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
if ( ! GetOpenFileName( & filename))
return 0 ;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( & si, sizeof (STARTUPINFO));
ZeroMemory( & pi, sizeof (PROCESS_INFORMATION));
bool ret = CreateProcess(filename.lpstrFile, "" ,NULL,NULL,FALSE,DEBUG_PROCESS,NULL,NULL, & si, & pi);
if (ret == false )
{
MessageBox(NULL, " 创建进程失败! " , "" , 0 );
return - 1 ;
}
// Anti-Anti-Debug
HideDebug(pi);
DEBUG_EVENT devent;
int DllCount = 0 ;
while (TRUE)
{
if (WaitForDebugEvent( & devent, 1 ))
{
switch (devent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
printf( " CREATE_PROCESS_DEBUG_EVENT\n " );
break ;
case CREATE_THREAD_DEBUG_EVENT:
printf( " CREATE_THREAD_DEBUG_EVENT\n " );
break ;
case EXCEPTION_DEBUG_EVENT:
// printf("EXCEPTION_DEBUG_EVENT\n");
switch (devent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
if (HasINT3)
{
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
printf( " Eax:%x\n,Esi:%x\n,Eip:%x\n,Ebp:%x\n " ,context.Eax,context.Esi,context.Eip,context.Ebp);
if (context.Eip == BreakPoint + 1 )
{
if ( ! CleanINT3(pi))
{
printf( " 清除断点失败! " );
}
printf( " Program Stopped At What We Want\n " );
char key[ 256 ];
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
ReadProcessMemory(pi.hProcess,(LPCVOID)context.Edx,key, sizeof (key),NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
printf( " 读出来的东西是 %s\n " ,key);
}
ResumeThread(pi.hThread);
}
break ;
case EXCEPTION_SINGLE_STEP:
printf( " 2 EXCEPTION_SINGLE_STEP\n " );
break ;
case EXCEPTION_ACCESS_VIOLATION:
printf( " 读写地址出错\n " );
printf( " %d,%x\n " ,devent.u.Exception.ExceptionRecord.ExceptionInformation[ 0 ],devent.u.Exception.ExceptionRecord.ExceptionAddress);
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
/* char Nop[3];
Nop[0] = 0x90;
Nop[1] = 0x90;
Nop[2] = 0x90;
PVOID pathAddress;
pathAddress = devent.u.Exception.ExceptionRecord.ExceptionAddress;
VirtualProtectEx(pi.hProcess,pathAddress,3,PAGE_READWRITE, &OldProtect);
WriteProcessMemory(pi.hProcess,pathAddress,Nop,3,NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,1,OldProtect,&OldProtect);
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); */
break ;
default :
break ;
}
break ;
case LOAD_DLL_DEBUG_EVENT:
// 获取DLL NAME太复杂,暂时做不到
DllCount ++ ;
printf( " %d,Program Loads a Dll From BaseImage:%x,ImageName:%x\n " ,DllCount,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);
if ( ! HasINT3)
{
if (IsUnpacked(pi))
{
printf( " UnPacked Success!!\n " );
WriteINT3(pi);
printf( " Write a INT3\n " );
}
}
break ;
case UNLOAD_DLL_DEBUG_EVENT:
printf( " UnLoad a Dll From BaseImage:%x,ImageName:%x\n " ,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);
if ( ! HasINT3)
{
if (IsUnpacked(pi))
{
printf( " UnPacked Success!!\n " );
WriteINT3(pi);
printf( " Write a INT3\n " );
}
}
break ;
case OUTPUT_DEBUG_STRING_EVENT:
break ;
case EXIT_PROCESS_DEBUG_EVENT:
printf( " 调试程序已退出 " );
break ;
default :
printf( " %d\n " ,devent.dwDebugEventCode);
break ;
}
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_CONTINUE);
}
else
{
}
}
// KeyMake中不要这两句
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0 ;
}
// AntiDebug:IsDebugPresent如何避开?
// 加壳处理不完善
//
#include " stdafx.h "
#include " windows.h "
#include " Commdlg.h "
#include " winnt.h "
BYTE INT3 = 0xCC ;
// 写入前的
BYTE Old;
// 页面属性
DWORD OldProtect;
// 是否已写入INT3
bool HasINT3 = false ;
bool IsFirstINT3 = true ;
DWORD BreakPoint = 0x00452191 ;
BYTE Org[ 8 ] = { 0xE8 , 0x4E };
// 判断是否解压完成
bool IsUnpacked(PROCESS_INFORMATION pi)
{
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
printf( " Exe Info:Eax:%x,Esp:%x,Eip:%x\n " ,context.Eax,context.Esp,context.Eip);
ResumeThread(pi.hThread);
BYTE mem[ 8 ];
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
ReadProcessMemory(pi.hProcess,(LPCVOID)BreakPoint, & mem, 8 ,NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
printf( " hex num is:%x,%x,%x,%x\n " ,mem[ 0 ],mem[ 1 ],mem[ 2 ],mem[ 3 ]);
if (mem[ 0 ] ^ 0xff == Org[ 0 ] && mem[ 1 ] ^ 0xff == Org[ 1 ])
{
// 不能乱调用
Old = mem[ 0 ];
return TRUE;
}
return false ;
}
// 写INT3
bool WriteINT3(PROCESS_INFORMATION pi)
{
// VirtualAllocEx(pi.hProcess,(LPVOID)0x0101259b,sizeof(INT3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
SuspendThread(pi.hThread);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & INT3, sizeof (INT3),NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
HasINT3 = ret;
ResumeThread(pi.hThread);
return ret;
}
// 改回去
bool CleanINT3(PROCESS_INFORMATION pi)
{
// SuspendThread(pi.hThread);
bool ret = WriteProcessMemory(pi.hProcess,(LPVOID)BreakPoint, & Old, sizeof (Old),NULL);
if (ret == false )
{
printf( " 改回去失败!\n " );
}
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
context.Eip -- ;
SetThreadContext(pi.hThread, & context);
printf( " 已经改回去了,Eax:%x\n " ,context.Eax);
return ret;
}
// 隐藏Debug
void HideDebug(PROCESS_INFORMATION pi)
{
BYTE ISDEBUGFLAG = 0x00 ;
int ISHEAPFLAG = 2 ;
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
// IsDebugPresent_Flag
WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x2 ), & ISDEBUGFLAG, 1 ,NULL);
// NTGlobal_Flag 用0D则为70 这个为0 防止其他调试器存在
WriteProcessMemory(pi.hProcess,(LPVOID)(context.Ebx + 0x68 ), & ISDEBUGFLAG, 1 ,NULL);
// GetProcessHeap_Flag
DWORD HeapAddress;
ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx + 0x18 ), & HeapAddress, sizeof (HeapAddress),NULL);
WriteProcessMemory(pi.hProcess,(LPVOID)HeapAddress, & ISHEAPFLAG, sizeof (ISHEAPFLAG),NULL);
ReadProcessMemory(pi.hProcess,(LPCVOID)(context.Ebx + 0x68 ), & ISDEBUGFLAG, 1 ,NULL);
printf( " NT_GLOBAL=%d\n " ,ISDEBUGFLAG);
ResumeThread(pi.hThread);
}
int main( int argc, char * argv[])
{
char f_name[ 256 ];
f_name[ 0 ] = NULL;
OPENFILENAME filename;
ZeroMemory( & filename, sizeof (OPENFILENAME));
filename.lStructSize = sizeof (OPENFILENAME);
filename.hwndOwner = NULL;
filename.lpstrFilter = " *.exe " ;
filename.lpstrFile = f_name;
filename.nMaxFile = 256 ;
filename.lpstrInitialDir = NULL;
filename.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
if ( ! GetOpenFileName( & filename))
return 0 ;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( & si, sizeof (STARTUPINFO));
ZeroMemory( & pi, sizeof (PROCESS_INFORMATION));
bool ret = CreateProcess(filename.lpstrFile, "" ,NULL,NULL,FALSE,DEBUG_PROCESS,NULL,NULL, & si, & pi);
if (ret == false )
{
MessageBox(NULL, " 创建进程失败! " , "" , 0 );
return - 1 ;
}
// Anti-Anti-Debug
HideDebug(pi);
DEBUG_EVENT devent;
int DllCount = 0 ;
while (TRUE)
{
if (WaitForDebugEvent( & devent, 1 ))
{
switch (devent.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
printf( " CREATE_PROCESS_DEBUG_EVENT\n " );
break ;
case CREATE_THREAD_DEBUG_EVENT:
printf( " CREATE_THREAD_DEBUG_EVENT\n " );
break ;
case EXCEPTION_DEBUG_EVENT:
// printf("EXCEPTION_DEBUG_EVENT\n");
switch (devent.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
if (HasINT3)
{
SuspendThread(pi.hThread);
CONTEXT context;
ZeroMemory( & context, sizeof (CONTEXT));
context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(pi.hThread, & context);
printf( " Eax:%x\n,Esi:%x\n,Eip:%x\n,Ebp:%x\n " ,context.Eax,context.Esi,context.Eip,context.Ebp);
if (context.Eip == BreakPoint + 1 )
{
if ( ! CleanINT3(pi))
{
printf( " 清除断点失败! " );
}
printf( " Program Stopped At What We Want\n " );
char key[ 256 ];
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,PAGE_READWRITE, & OldProtect);
ReadProcessMemory(pi.hProcess,(LPCVOID)context.Edx,key, sizeof (key),NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint, 1 ,OldProtect, & OldProtect);
printf( " 读出来的东西是 %s\n " ,key);
}
ResumeThread(pi.hThread);
}
break ;
case EXCEPTION_SINGLE_STEP:
printf( " 2 EXCEPTION_SINGLE_STEP\n " );
break ;
case EXCEPTION_ACCESS_VIOLATION:
printf( " 读写地址出错\n " );
printf( " %d,%x\n " ,devent.u.Exception.ExceptionRecord.ExceptionInformation[ 0 ],devent.u.Exception.ExceptionRecord.ExceptionAddress);
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED);
/* char Nop[3];
Nop[0] = 0x90;
Nop[1] = 0x90;
Nop[2] = 0x90;
PVOID pathAddress;
pathAddress = devent.u.Exception.ExceptionRecord.ExceptionAddress;
VirtualProtectEx(pi.hProcess,pathAddress,3,PAGE_READWRITE, &OldProtect);
WriteProcessMemory(pi.hProcess,pathAddress,Nop,3,NULL);
VirtualProtectEx(pi.hProcess,(LPVOID)BreakPoint,1,OldProtect,&OldProtect);
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_EXCEPTION_NOT_HANDLED); */
break ;
default :
break ;
}
break ;
case LOAD_DLL_DEBUG_EVENT:
// 获取DLL NAME太复杂,暂时做不到
DllCount ++ ;
printf( " %d,Program Loads a Dll From BaseImage:%x,ImageName:%x\n " ,DllCount,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);
if ( ! HasINT3)
{
if (IsUnpacked(pi))
{
printf( " UnPacked Success!!\n " );
WriteINT3(pi);
printf( " Write a INT3\n " );
}
}
break ;
case UNLOAD_DLL_DEBUG_EVENT:
printf( " UnLoad a Dll From BaseImage:%x,ImageName:%x\n " ,devent.u.LoadDll.lpBaseOfDll,devent.u.LoadDll.lpImageName);
if ( ! HasINT3)
{
if (IsUnpacked(pi))
{
printf( " UnPacked Success!!\n " );
WriteINT3(pi);
printf( " Write a INT3\n " );
}
}
break ;
case OUTPUT_DEBUG_STRING_EVENT:
break ;
case EXIT_PROCESS_DEBUG_EVENT:
printf( " 调试程序已退出 " );
break ;
default :
printf( " %d\n " ,devent.dwDebugEventCode);
break ;
}
ContinueDebugEvent(pi.dwProcessId,pi.dwThreadId,DBG_CONTINUE);
}
else
{
}
}
// KeyMake中不要这两句
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0 ;
}
目前版本功能:
1.启动目标程序
2.向指定位置写入INT3断点
3.读取/设置指定位置寄存器值
4.读取/修改指定位置内存值
5.解压一些压缩和加密壳
6.一些Anti-Anti-Debug功能