DbgUiRemoteBreakin反调试

DbgUiRemoteBreakin是ntdll提供的用于在目标进程中创建远线程后下软件断点的函数

当我们用OD附加调试时,CreateRemoteThread函数在目标程序中创建了一个远程线程,然后在远程线程中调用DbgUiRemoteBreakin函数,DbgUiRemoteBreakin内部调用了DbgBreakPoint函数,DbgBreakPoint函数内部下了一个int 3断点,触发异常让操作系统运行异常处理程序,然后操作系统把控制权交管给调试器
ps:DbgUiIssueRemoteBreakin内部调用了DbgUiRemoteBreakin

反调试
hook DbgUiRemoteBreakin 函数,在内部直接调用ExitProcess()退出程序,不让程序被调试器成功附加
这里我们使用创建TLS回调的方式hook DbgUiRemoteBreakin (记录一下TLS创建流程)

/// <summary>
///添加文件tls.c
/// </summary>
//tls.c start
#include <Windows.h>
#pragma data_seg(".tls")
#pragma comment(linker, "/INCLUDE:__tls_used")
int _tls_index = 0;
int _tls_start = 0;
int _tls_end = 0;
int __xl_a = 0;
int __xl_z = 0;
extern PIMAGE_TLS_CALLBACK tls_callbacktbl[];//TLS回调函数数组
IMAGE_TLS_DIRECTORY32 _tls_used =
{
    (DWORD)&_tls_start,
    (DWORD)&_tls_end,
    (DWORD)&_tls_index,
    (DWORD)tls_callbacktbl,
    0,
    0
};
#pragma data_seg(".tls$ZZZ")
#pragma data_seg(".CRT$XLA")
#pragma data_seg(".CRT$XLZ")
#pragma data_seg(".rdata$T")
//tls.c end
# include<stdio.h>
# include<windows.h>
void HookDbgUiRemoteBreakin();
/// <summary>
///定义TLS回调函数
/// </summary>
void NTAPI TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved)
{
	switch (Reason)
	{
	case DLL_PROCESS_ATTACH:
		HookDbgUiRemoteBreakin();
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
	case DLL_PROCESS_DETACH:
		break;
	}
}
/// <summary>
///注册TLS回调函数
/// </summary>
extern "C" PIMAGE_TLS_CALLBACK tls_callbacktbl[] = { TLS_CALLBACK, 0 };
int main()
{
	static int i = 0;
	while (1)
	{
		Sleep(1000);
		printf("当前程序运行中. EIP 位置 等于 %d \r\n", i++);
	}
	return 0;
	system("pause");
}
void HookDbgUiRemoteBreakin()
{
	BYTE	bBuffer[0x10] = { 0 };
	DWORD	dwBreakAddress;					//DbgUiRemoteBreakin函数的地址
	DWORD	dwOldProtect;
	DWORD	dwNum;

	dwBreakAddress = (DWORD)GetProcAddress(LoadLibrary(L"ntdll.dll"), "DbgUiRemoteBreakin");
	if (dwBreakAddress == 0)
		return ;
	bBuffer[0] = 0xE9;									//jmp指令字节码
	*((DWORD*)(bBuffer + 1)) = (DWORD)ExitProcess - dwBreakAddress - 5;			//ExitProcess函数偏移地址

	VirtualProtect((LPVOID)dwBreakAddress, 0x10, PAGE_EXECUTE_READWRITE, &dwOldProtect);
	WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwBreakAddress, bBuffer, 5, (SIZE_T*)&dwNum);
	VirtualProtect((LPVOID)dwBreakAddress, 0x10, dwOldProtect, &dwOldProtect);
}

反反调试
对照着本进程自身加载的未被hook的系统模块来复原目标进程被hook的系统模块
关键代码实现

# include<Windows.h>
# include<Tlhelp32.h>
# include<stdio.h>
//==================================================================
//函数名: GetProcessPID
//功能:获取指定进程名的进程的PID
//输入参数1:IN,目标进程的名称
//返回值:获取成功返回PID,获取失败返回NULL
//==================================================================
DWORD GetProcessPID(PCWCHAR name)
{

    //初始化进程快照
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProcessSanp = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);  //获得快照句柄

    Process32First(hProcessSanp, &pe32);  //获取第一个进程
    do
    {


        if (wcscmp(name, pe32.szExeFile) == 0)
        {
            CloseHandle(hProcessSanp);//关闭快照句柄,避免内存泄漏
            return pe32.th32ProcessID; //注意这里使用的权限

        }
    } while (Process32Next(hProcessSanp, &pe32));

    CloseHandle(hProcessSanp);//关闭快照句柄,避免内存泄漏
    return NULL;


}
//==================================================================
//函数名: GetModuleInfo
//功能:获取指定进程的对应模块名的模块的信息  
//输入参数1:IN,目标进程的PID
//输入参数2:IN,指定模块的模块名
//输入参数3:OUT,模块的信息结构体 PMODULEENTRY32
//返回值:获取成功返回TRUE,获取失败返回FALSE
//注意:模块名区分大小写
//==================================================================
BOOL GetModuleInfo(DWORD pid, PCWCHAR ModuleName, OUT PMODULEENTRY32 pme32)
{
    MODULEENTRY32 me32;
    me32.dwSize = sizeof(MODULEENTRY32);                                    //在使用这个结构前,先设置它的大小
    HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);  //HANDLE也是属于句柄,是通用句柄  ,HWND是窗口句柄

    if (hModuleSnap == INVALID_HANDLE_VALUE)     //INVALID_HANDLE_VALUE表示无效的句柄
    {
        printf("模块读取失败\n");
        return FALSE;
    }
    BOOL bMore = Module32First(hModuleSnap, &me32);    //获取第一个模块信息
    if (wcscmp(ModuleName, me32.szModule) == 0)
    {
        //printf("module name=%ws\n", me32.szModule);
        *pme32 = me32;
        return TRUE;
    }
    while (bMore)
    {
        bMore = Module32Next(hModuleSnap, &me32);
        if (wcscmp(ModuleName, me32.szModule) == 0)
        {
            //printf("module name=%ws\n", me32.szModule);
            *pme32 = me32;
            return TRUE;
        }
    }
    return FALSE;
}
//==================================================================
//函数名: RecoverModule
//功能:恢复目标进程被hook的系统模块  
//输入参数1:IN,目标进程的进程名
//输入参数2:IN,指定模块的模块名
//输入参数3:IN,被hook的位置与被hook模块的基地址的偏移
//输入参数4:IN,被hook的长度
//返回值:恢复成功返回TRUE,恢复失败返回FALSE
//==================================================================
BOOL RecoverModule(LPCWCHAR ExeName, LPCWCHAR ModuleName, DWORD Offset, DWORD Length)
{
    //devenv.exe
    DWORD ExePID =  GetProcessPID(ExeName);
    printf("ExePID=%d\n", ExePID);
    if (ExePID == NULL)
    {
        printf("获取程序PID失败\n");
        return FALSE;
    }
    MODULEENTRY32 me;
    BOOL result = GetModuleInfo(ExePID, ModuleName, &me);
    if (result == FALSE)
    {
        printf("获取模块信息失败\n");
        return FALSE;
    }
    printf("module name=%ws\n", me.szModule);
    HMODULE hModule = GetModuleHandle(ModuleName);
    LONG StartPos = (LONG)hModule + (LONG)Offset;
    HANDLE hExe = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ExePID);
    if (result == 0)
    {
        printf("打开进程失败\n");
        return FALSE;
    }
    char buffer[256];
    DWORD NumberOfBytesRead;
    DWORD NumberOfBytesWritten;
    DWORD OldProtect;
    result = ReadProcessMemory(GetCurrentProcess(), (PVOID)StartPos, buffer, Length, &NumberOfBytesRead);
    printf("NumberOfBytesRead=%d\n", NumberOfBytesRead);
    if (result == 0)
    {
        printf("读内存失败,错误信息=%d\n",GetLastError());
        return FALSE;
    }
    result = VirtualProtectEx(hExe, (PVOID)StartPos, Length, PAGE_EXECUTE_READWRITE, &OldProtect);
    if (result == 0)
    {
        printf("更改目标程序内存属性失败,错误信息=%d\n", GetLastError());
        return FALSE;
    }
    result = WriteProcessMemory(hExe, (PVOID)StartPos, buffer, Length, &NumberOfBytesWritten);
    if (result == 0)
    {
        printf("写内存失败\n");
        return FALSE;
    }
    result = VirtualProtectEx(hExe, (PVOID)StartPos, Length, OldProtect, &OldProtect);
    if (result == 0)
    {
        printf("恢复目标程序内存属性失败\n");
        return FALSE;
    }
    CloseHandle(hExe);
    return TRUE;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值