调试器原理初步学习

- Linux调试器原理:

ptrace: long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

Wikipedia:ptrace is a system call found in Unix and several Unix-like operating systems. By using ptrace (the name is an abbreviation of "process trace") one process can control another, enabling the controller to inspect and manipulate the internal state of its target.
手册: http://man7.org/linux/man-pages/man2/ptrace.2.html

相关文章Process Tracing Using Ptrace

// 32-bit系统
//其中的一个例子,打印当前的目录项
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syscall.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>


int main(void)
{
        long long counter = 0;  /*  machine instruction counter */
        int wait_val;           /*  child's return value        */
        int pid;                /*  child's process id          */

        puts("Please wait");

        switch (pid = fork()) {
        case -1:
                perror("fork");
                break;
        case 0: /*  child process starts        */
                ptrace(PTRACE_TRACEME, 0, 0, 0);
                /* 
                 *  must be called in order to allow the
                 *  control over the child process
                 */ 
                execl("/bin/ls", "ls", NULL);
                /*
                 *  executes the program and causes
                 *  the child to stop and send a signal 
                 *  to the parent, the parent can now
                 *  switch to PTRACE_SINGLESTEP   
                 */ 
                break;
                /*  child process ends  */
        default:/*  parent process starts       */
                wait(&wait_val); 
                /*   
                 *   parent waits for child to stop at next 
                 *   instruction (execl()) 
                 */
                while (wait_val == 1407 ) {
                        counter++;
                        if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0)
                                perror("ptrace");
                        /* 
                         *   switch to singlestep tracing and 
                         *   release child
                         *   if unable call error.
                         */
                        wait(&wait_val);
                        /*   wait for next instruction to complete  */
                }
                /*
                 * continue to stop, wait and release until
                 * the child is finished; wait_val != 1407
                 * Low=0177L and High=05 (SIGTRAP)
                 */
        }
        printf("Number of machine instructions : %lld\n", counter);
        return 0;
}

寄存器在int中断时会在内核栈中压入各寄存器的值,形成一个数组,寄存器对应的下标可以在文件/usr/include/x86_64-linux-gnu/sys/reg.h中查看,这个是64位系统的。于是在使用PTRACE_PEEKUSER指令获取寄存器值得时候,需要"*8",因为64位系统中一个整型存储单元为8字节。32位系统则乘4。

Linux中使用ptrace进行程序的调试,并且通过request参数传递调试命令,以pid参数指定被处理进程,addr指定内存地址,data则是用来存取数据。
其他练习: ptraceDemo

- Windows 调试器原理

Windows提供的Win32 Debug API:

  1. BOOL ContinueDebugEventDWORD dwProcess,DWORD dwThreadId,DWORD dwContinueStatus);
  2. BOOL DebugActiveProcessDWORD dwProcessId);
  3. BOOL DebugActiveProcessStopDWORD dwProcessId);
  4. VOID DebugBreakVOID);
  5. VOID DebugBreakProcessHANDLE hProcess);
  6. VOID FatalExitint ExitCode);
  7. BOOL FlushInstructionCacheHANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize);
  8. BOOL GetThreadContextHANDLE hThread,LPCONTEXT lpContext);
  9. BOOL GetThreadSelectorEntryHANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry);
  10. IsDebuggerPresentVOID);
  11. VOID OutDebugStringLPCYSTR lpOutputString);
  12. BOOL ReadProcessMemoryHANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T * lpNumberOfBytesRead);
  13. BOOL SetThreadContextHANDLE hThread,LPCONTEXT lpContext);
  14. BOOL WaitForDebugEventLPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds);
  15. BOOL WriteProcessMemoryHANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T * lpNumberOfBytesWritten);

DEBUG_EVENT结构:

typedef struct _DEBUG_EVENT { // de
	DWORD dwDebugEventCode;
	DWORD dwProcessId;
	DWORD dwThreadId;
	union {
		EXCEPTION_DEBUG_INFO Exception;
		CREATE_THREAD_DEBUG_INFO CreateThread;
		CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
		EXIT_THREAD_DEBUG_INFO ExitThread;
		EXIT_PROCESS_DEBUG_INFO ExitProcess;
		LOAD_DLL_DEBUG_INFO LoadDll;
		UNLOAD_DLL_DEBUG_INFO UnloadDll;
		OUTPUT_DEBUG_STRING_INFO DebugString;
		RIP_INFO RipInfo;
	} u;
} DEBUG_EVENT;

1. 可以创建一个新进程以供调试:

CreateProcess
The CreateProcess function creates a new process and its primary thread. The new process executes the specified executable file.
BOOL CreateProcess(
LPCTSTR lpApplicationName,
// pointer to name of executable module

LPTSTR lpCommandLine,
// pointer to command line string

LPSECURITY_ATTRIBUTES lpProcessAttributes,
// pointer to process security attributes

LPSECURITY_ATTRIBUTES lpThreadAttributes,
// pointer to thread security attributes

BOOL bInheritHandles,
// handle inheritance flag

DWORD dwCreationFlags,
// creation flags

LPVOID lpEnvironment,
// pointer to new environment block

LPCTSTR lpCurrentDirectory,
// pointer to current directory name

LPSTARTUPINFO lpStartupInfo,
// pointer to STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation
// pointer to PROCESS_INFORMATION
);

2. 将调试器捆绑到一个正在运行的进程上。
可以使用DebugActiveProcess进行附加,成功后效果类似于利用DEBUG_ONLY_THIS_PROCESS标志创建的新进程。
在NT内核中,对创建时有安全描述符的进程进行附加时将失败;而在win9x中仅在进程标识符失效时失败。


创建进程test:

#include "windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"

int main(){
	
	PROCESS_INFORMATION pi;
	STARTUPINFO         si;
	DEBUG_EVENT         devent;
	TCHAR               cmdLine[] = TEXT("xxxxxx");    // 被调试进程,有时采用相对路径会失败,使用绝对路径
	int counter = 0;
	if(CreateProcess(0, cmdLine, 0, 0, FALSE, DEBUG_ONLY_THIS_PROCESS, 0, 0, &si, &pi)){
		while(TRUE){
			if(WaitForDebugEvent(&devent, 300)){     // 等待300毫秒
				switch(devent.dwDebugEventCode){     // 调试事件码
					case CREATE_PROCESS_DEBUG_EVENT:   // 进程创建
					// 处理代码
						printf("debugee is created...\n");
						break;
					case EXIT_PROCESS_DEBUG_EVENT:     // 调试异常事件
					// 处理代码
						printf("debugee process is to exit...\n");
						break;
					case EXCEPTION_DEBUG_EVENT:     // 被调试进程将结束运行
					// 处理代码
						printf("get a exception event...\n");
						break;
				}
				ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);// 以忽略异常的方式继续执行
				counter ++ ;
			}
			else{
				printf("process end...\n");
				break;
			}
		}
	}
	else{
		MessageBox(NULL, TEXT("Create Process Error!!"), TEXT("Fatal Error"), MB_OK);
	}
	printf("%d\n", counter);
	return 0;
}

参考:《加密与解密(第四版)》

posted @ 2019-03-20 19:49  Bl0od  阅读(357)  评论(0编辑  收藏  举报