#include "stdafx.h"
#include <stdlib.h>
#define WINVER 0x0501
#include <windows.h>
BOOL
DbgNewProcess( LPTSTR szCmdLine)
{
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInfo;
memset ( &StartupInfo , NULL , sizeof ( STARTUPINFO ) ) ;
memset ( &ProcessInfo , NULL , sizeof ( PROCESS_INFORMATION ) ) ;
StartupInfo.cb = sizeof ( STARTUPINFO ) ;
//-- create the Debuggee process
if( !CreateProcess(
0L,
szCmdLine,
(LPSECURITY_ATTRIBUTES) 0L,
(LPSECURITY_ATTRIBUTES) 0L,
TRUE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
(LPVOID) 0L,
(LPTSTR) 0L,
&StartupInfo, &ProcessInfo ) )
{
TCHAR szMsg[MAX_PATH];
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) szMsg,
MAX_PATH,
NULL
);
printf("Failed in CreateProcess() with error:\n ");
printf(szMsg); printf("\n");
return( FALSE );
}
else
{
CloseHandle( ProcessInfo.hProcess );
CloseHandle( ProcessInfo.hThread );
}
return( TRUE );
}
#define MAX_DBG_EVENT 9
LPTSTR DbgEventName[ MAX_DBG_EVENT+1] = {
"EXCEPTION_DEBUG_EVENT",
"CREATE_THREAD_DEBUG_EVENT",
"CREATE_PROCESS_DEBUG_EVENT",
"EXIT_THREAD_DEBUG_EVENT",
"EXIT_PROCESS_DEBUG_EVENT",
"LOAD_DLL_DEBUG_EVENT",
"UNLOAD_DLL_DEBUG_EVENT",
"OUTPUT_DEBUG_STRING_EVENT",
"RIP_EVENT",
"Unknown Debug Event"
};
//在处理完调试事件后,调试器会调用 ContinueDebugEvent API来恢复调试事件
BOOL DbgMainLoop(DWORD dwWaitMS)
{
DEBUG_EVENT DbgEvt; // debugging event information
DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation
BOOL bExit=FALSE;
while(!bExit)
{
// Wait for a debugging event to occur. The second parameter indicates
// number of milliseconds to wait for a debugging event. If the parameter
// is INFINITE the function does not return until a debugging event occurs.
if(!WaitForDebugEvent(&DbgEvt, dwWaitMS))
{
printf("WaitForDebugEvent() returned False %d.\n",GetLastError());
bExit=TRUE;
continue;
}
// Process the debugging event code.
printf("Debug event received from process %d thread %d: %s.\n",
DbgEvt.dwProcessId, DbgEvt.dwThreadId,
DbgEventName[DbgEvt.dwDebugEventCode>
MAX_DBG_EVENT?MAX_DBG_EVENT:
DbgEvt.dwDebugEventCode-1]);
switch (DbgEvt.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
// Process the exception code. When handling
// exceptions, remember to set the continuation
// status parameter (dwContinueStatus). This value
// is used by the ContinueDebugEvent function.
printf("-Debuggee breaks into debugger; press any key to continue.\n");
getchar();
//return TRUE;
switch (DbgEvt.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_BREAKPOINT:
// First chance: Display the current
// instruction and register values.
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
case EXCEPTION_SINGLE_STEP:
// First chance: Update the display of the
// current instruction and register values.
break;
case DBG_CONTROL_C:
// First chance: Pass this on to the system.
// Last chance: Display an appropriate error.
break;
default:
// Handle other exceptions.
break;
}
case CREATE_THREAD_DEBUG_EVENT:
// As needed, examine or change the thread's registers
// with the GetThreadContext and SetThreadContext functions;
// and suspend and resume thread execution with the
// SuspendThread and ResumeThread functions.
break;
case CREATE_PROCESS_DEBUG_EVENT:
// As needed, examine or change the registers of the
// process's initial thread with the GetThreadContext and
// SetThreadContext functions; read from and write to the
// process's virtual memory with the ReadProcessMemory and
// WriteProcessMemory functions; and suspend and resume
// thread execution with the SuspendThread and ResumeThread
// functions. Be sure to close the handle to the process image
// file with CloseHandle.
break;
case EXIT_THREAD_DEBUG_EVENT:
// Display the thread's exit code.
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Display the process's exit code.
bExit=TRUE;
break;
case LOAD_DLL_DEBUG_EVENT:
// Read the debugging information included in the newly
// loaded DLL. Be sure to close the handle to the loaded DLL
// with CloseHandle.
break;
case UNLOAD_DLL_DEBUG_EVENT:
// Display a message that the DLL has been unloaded.
break;
case OUTPUT_DEBUG_STRING_EVENT:
// Display the output debugging string.
break;
}
// Resume executing the thread that reported the debugging event.
ContinueDebugEvent(DbgEvt.dwProcessId,
DbgEvt.dwThreadId, dwContinueStatus);
//Enables a debugger to continue a thread that previously reported a debugging event.
}
return TRUE;
}
void Help()
{
printf ( "TinyDbgr <PID of Program to Debug>|\n "
"<Full Exe File Name> [Prgram Parameters]\n" ) ;
}
int main(int argc, char* argv[])
{
if(argc<=1)
{
Help(); return -1;
}
if (strstr(strupr(argv[1]),".EXE"))//将字符串s转换为大写形式说明:只转换s中出现的小写字母,不改变其它字符...
{//从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。
TCHAR szCmdLine[ MAX_PATH ] ;
szCmdLine[ 0 ] = '\0' ;
for ( int i = 1 ; i < argc ; i++ )
{
strcat ( szCmdLine , argv[ i ] ) ;
if ( i < argc )
{
strcat ( szCmdLine , " " ) ;
}
}
if(!DbgNewProcess(szCmdLine))
{
return -2;
}
}
else
{
if(!DebugActiveProcess(atoi(argv[1])))//If the function succeeds, the return value is nonzero.
{
printf("Failed in DebugActiveProcess() with %d.\n",GetLastError());
return -2;
}
if(argc>2 && stricmp(argv[2],"-e")==0)
{
// try the DebugSetProcessKillOnExit() API
if(!DebugSetProcessKillOnExit(FALSE))
{//Sets the action to be performed when the calling thread exits.
printf("Failed in DebugSetProcessKillOnExit() with %d.\n",GetLastError());
}
}
if(argc>2 && stricmp(argv[2],"-s")==0)
{
DbgMainLoop(10);
// try the DebugActiveProcessStop() API
if(!DebugActiveProcessStop(atoi(argv[1])))
{
printf("Failed in DebugActiveProcessStop() with %d.\n",GetLastError());
}
else
printf("Detach debuggee successfully.\n");
return 0;
}
}
return DbgMainLoop(INFINITE);
}
上面是学习的小调试器代码 看看就行·························
两种方式:
1 输入PID 附加到已经启动的进程
DebugActiveProcess 实现 附加功能
BOOL WINAPI DebugSetProcessKillOnExit(
_In_ BOOL KillOnExit
);
If this parameter is TRUE, the thread terminates all attached processes on exit (note that this is the default). Otherwise, the thread detaches from all processes being debugged on exit.
2 打开程序调试
通过创建程序时 带调试
CreateProcess(
0L,
szCmdLine,
(LPSECURITY_ATTRIBUTES) 0L,
(LPSECURITY_ATTRIBUTES) 0L,
TRUE,
DEBUG_PROCESS | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
(LPVOID) 0L,
(LPTSTR) 0L,
&StartupInfo, &ProcessInfo)
BOOL WINAPI WaitForDebugEvent( _Out_ LPDEBUG_EVENT lpDebugEvent, //保存 收到的调试事件 _In_ DWORD dwMilliseconds //指定等待的毫秒数 INFINITE 无限期等待 );
来供 调试器等待和接收调试事件
在处理完调试事件后,调试器会调用 ContinueDebugEvent API来恢复调试事件
BOOL WINAPI ContinueDebugEvent( _In_ DWORD dwProcessId, _In_ DWORD dwThreadId, _In_ DWORD dwContinueStatus );
最后附带一个修改程序的例子:
#include "stdio.h"
#include "tchar.h"
#include "windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
STARTUPINFO stSi;
PROCESS_INFORMATION stPi;
DEBUG_EVENT stDe;
int nAddrOfBreakPoint = 0x0040E813; //需要下断点的地址
int nAddrOfPatch = 0x004010B8; //需要打补丁处的地址
unsigned char cOldByte; //用于保存nAddrOfBreakPoint断点处的原指令
unsigned char cBreakPoint = 0xCC; //int 3指令
unsigned char cPatchByte = 0x75; //补丁字节
CONTEXT stThreadContext;
BOOL bCreated = FALSE;
BOOL bFinished = FALSE;
//LPTSTR szCmdLine = _tcsdup(TEXT("mengmeng.exe"));
LPTSTR szCmdLine = _T("mengmeng.exe");
GetStartupInfo(&stSi);
bCreated = CreateProcess(NULL,szCmdLine,NULL,NULL,FALSE,DEBUG_ONLY_THIS_PROCESS,NULL,NULL,&stSi,&stPi);
if(!bCreated){
MessageBox(GetActiveWindow(),TEXT("不能打开test.exe文件!"),TEXT("Result"),MB_OK);
//不能打开test.exe时清除资源
if(szCmdLine!=NULL) free(szCmdLine);
return 0;
}
//开始调试运行,等待调试事件发生
while(WaitForDebugEvent(&stDe,INFINITE)){//有调试事件发生
switch(stDe.dwDebugEventCode){
case CREATE_PROCESS_DEBUG_EVENT:
//写断点(int 3[0xCC])到nAddrOfBreakPoint,之前要保存原始指令
ReadProcessMemory(stPi.hProcess,(LPVOID)nAddrOfBreakPoint,&cOldByte,1,NULL);
WriteProcessMemory(stPi.hProcess,(LPVOID)nAddrOfBreakPoint,&cBreakPoint,1,NULL);
break;
case EXCEPTION_DEBUG_EVENT:
if(stDe.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT){//断点异常
//若不是在nAddrOfBreakPoint处中断,则继续等待
stThreadContext.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(stPi.hThread,&stThreadContext);
if(stThreadContext.Eip!=nAddrOfBreakPoint+1) break;
//执行内存补丁
WriteProcessMemory(stPi.hProcess,(LPVOID)0x004010B8,&cPatchByte,1,NULL);
//恢复nAddrOfBreakPoint原始指令,并重新执行该指令
WriteProcessMemory(stPi.hProcess,(LPVOID)nAddrOfBreakPoint,&cOldByte,1,NULL);
stThreadContext.ContextFlags = CONTEXT_FULL;
GetThreadContext(stPi.hThread,&stThreadContext);
stThreadContext.Eip = nAddrOfBreakPoint;
SetThreadContext(stPi.hThread,&stThreadContext);
}
break;
case EXIT_PROCESS_DEBUG_EVENT:
bFinished = TRUE;
}
ContinueDebugEvent(stPi.dwProcessId,stPi.dwThreadId,DBG_CONTINUE);//继续让被调试的程序执行
if(bFinished)break;
}
//破解成功后清除内存资源
if(szCmdLine!=NULL) free(szCmdLine);
CloseHandle(stPi.hThread);
CloseHandle(stPi.hProcess);
return 0;
}