调试器学习

#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:
  ");
		printf(szMsg);	printf("
");
		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.
",GetLastError());
			bExit=TRUE;
			continue;
		}
 
		// Process the debugging event code. 
		printf("Debug event received from process %d thread %d: %s.
",
			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.
");
				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>|
    "
             "<Full Exe File Name> [Prgram Parameters]
" ) ;
}
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 ] = '' ;

		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.
",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.
",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.
",GetLastError());
			}
			else
				printf("Detach debuggee successfully.
");
			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;
}

















原文地址:https://www.cnblogs.com/zcc1414/p/3982428.html