- 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
", 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:
- BOOL ContinueDebugEvent(DWORD dwProcess,DWORD dwThreadId,DWORD dwContinueStatus);
- BOOL DebugActiveProcess(DWORD dwProcessId);
- BOOL DebugActiveProcessStop(DWORD dwProcessId);
- VOID DebugBreak(VOID);
- VOID DebugBreakProcess(HANDLE hProcess);
- VOID FatalExit(int ExitCode);
- BOOL FlushInstructionCache(HANDLE hProcess,LPCVOID lpBaseAddress,SIZE_T dwSize);
- BOOL GetThreadContext(HANDLE hThread,LPCONTEXT lpContext);
- BOOL GetThreadSelectorEntry(HANDLE hThread,DWORD dwSelector,LPLDT_ENTRY lpSelectorEntry);
- IsDebuggerPresent(VOID);
- VOID OutDebugString(LPCYSTR lpOutputString);
- BOOL ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,SIZE_T nSize,SIZE_T * lpNumberOfBytesRead);
- BOOL SetThreadContext(HANDLE hThread,LPCONTEXT lpContext);
- BOOL WaitForDebugEvent(LPDEBUG_EVENT lpDebugEvent,DWORD dwMilliseconds);
- BOOL WriteProcessMemory(HANDLE 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...
");
break;
case EXIT_PROCESS_DEBUG_EVENT: // 调试异常事件
// 处理代码
printf("debugee process is to exit...
");
break;
case EXCEPTION_DEBUG_EVENT: // 被调试进程将结束运行
// 处理代码
printf("get a exception event...
");
break;
}
ContinueDebugEvent(devent.dwProcessId, devent.dwThreadId, DBG_CONTINUE);// 以忽略异常的方式继续执行
counter ++ ;
}
else{
printf("process end...
");
break;
}
}
}
else{
MessageBox(NULL, TEXT("Create Process Error!!"), TEXT("Fatal Error"), MB_OK);
}
printf("%d
", counter);
return 0;
}
参考:《加密与解密(第四版)》