#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; }