吾爱汇编

 找回密码
 立即注册

QQ登录

绑定QQ避免忘记帐号

查看: 4532|回复: 6

[C/C++] 偶然间想到一种无需DLL跨进程HOOK的方法

[复制链接]
李沉舟 发表于 2016-8-17 09:53 | 显示全部楼层 |阅读模式

这个方法的原理就是:
①首先在API头部写一个CC断点
②中断的时候程序收到消息,并且读出参数

需要注意的地方只有修正EIP寄存器,和读取参数的问题。
因为API采用STDCALL的方式调用,所以参数是从右向左压进堆栈的。
还有就是API的开头是
mov edi,edi
push ebp
mov ebp,esp

我们要注意,因为我们是在头部断下的,还没有执行push ebp,而执行了push ebp之后esp会减4,也就是说,我们在头部中断的时候要把esp-4才能拿ESP来读取参数!

还要注意的就是,如何不执行API直接跳转到返回地址,一般ESP储存的地址指向的就是返回地址,所以我们只要把EIP修改就好,如果你要设置返回值,那么就修改EAX为返回值。(记得修正ESP)

如何单步?这也是一个问题,我们可以在第一条指令中断之后,在第二条指令下CC断点,同时还原第一条指令,等到第二条指令触发中断事件时,我们再在第一条指令上下CC断点,再还原第二条指令,这就模拟了一次单步。

我把代码贴出来,使用VC2010编译

#include <stdio.h>
#include <windows.h>

#define SE_DEBUG_PRIVILEGE 20
typedef  DWORD(WINAPI *PRtlAdjustPrivilege)   ///未文档化函数声明
(
ULONG    Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled
);

void WINAPI AdjustPrivilege()         ///ntdll中的提权函数
{
        BOOLEAN Enabled;
        PRtlAdjustPrivilege RtlAdjustPrivilege = (PRtlAdjustPrivilege)GetProcAddress(LoadLibrary((LPCSTR)"ntdll.dll"), "RtlAdjustPrivilege");
        RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Enabled);
}

int main(void)
{
    DWORD pid;
    DWORD lpapi;
    BYTE code[2];
    BYTE _code;
    BYTE cc = 0xCC;
    PDWORD p;
    HANDLE hProcess;
    HANDLE hThread;
    HMODULE hMod;
    int yes = TRUE;
    DEBUG_EVENT dbg;
    CONTEXT ct;

    int wType;
    char text[255];
    char caption[255];
    int hwin;
    DWORD pt;

    char ch;

    AdjustPrivilege(); ///提升进程权限到DEBUG
    printf("请输入要HOOK的进程ID:____\b\b\b\b");
    scanf("%d", &pid); ///获取要HOOK的进程的ID
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
    hMod = GetModuleHandle("user32.dll"); ///获取模块句柄
    if (!hMod)
        hMod = LoadLibrary("user32.dll"); ///如果没有获取到模块句柄,则加载模块
    lpapi = (DWORD)GetProcAddress(hMod, "MessageBoxA"); ///取API地址
    ReadProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///获取API头部两字节数据,即第一条指令
    ReadProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL); ///获取API第二条指令第一字节数据
    WriteProcessMemory(hProcess, (LPVOID)lpapi, &cc, 1, NULL);
    DebugActiveProcess(pid); ///开启调试会话
    while (yes)
    {
        if(WaitForDebugEvent(&dbg, 20) == 0) ///如果当前还没有触发调试信息
        {
            Sleep(50);
            continue;
        }
        if(dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) ///如果是调试事件
        {
            if(dbg.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT) ///如果不是中断事件
            {
                ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); ///继续调试
                continue;
            }
            if((DWORD)dbg.u.Exception.ExceptionRecord.ExceptionAddress == lpapi)
            {
                hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dbg.dwThreadId); ///打开线程
                ct.ContextFlags = CONTEXT_ALL;
                SuspendThread(hThread); ///暂停线程,否则不可以读取线程寄存器信息
                GetThreadContext(hThread, &ct); ///读取线程寄存器信息
                printf("拦截到进程MessageBoxA调用!\n");
                ///这里为什么要-4?因为函数头部是push ebp,mov ebp,esp,而push了ebp之后,esp会-4,我们下CC断点的地方是函数头部
                ///所以此时ESP还未-4,所以我们读取的时候要把ESP-4
                ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x10), &hwin, 4, NULL); ///读取HWND参数
                ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0xC), &pt, 4, NULL); ///读取Text参数的指针
                ReadProcessMemory(hProcess, (LPVOID)pt, text, 255, NULL); ///读取Text参数
                ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x8), &pt, 4, NULL); ///读取Caption参数的指针
                ReadProcessMemory(hProcess, (LPVOID)pt, caption, 255, NULL); ///读取Caption参数
                ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x4), &wType, 4, NULL); ///读取wType参数
                ReadProcessMemory(hProcess, (LPVOID)(ct.Esp), &pt, 4, NULL); ///读取返回地址
                printf("hwnd:%d\nlpText:%s\nlpCaption:%s\nwType:%d\n", hwin, text, caption, wType);
                printf("返回地址:%#x\n", pt);
                printf("输入Y允许执行,输入N不允许执行,输入其他则退出:_\b");
                fflush(stdin);
                scanf("%c", &ch);
                if(ch == 'Y' || ch == 'y')
                {
                    ///允许执行,模拟OD单步事件
                    WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &cc, 1, NULL); ///在API的第二条指令下断点
                    WriteProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///还原第一条指令
                    ct.Eip--; ///修改EIP寄存器,使其-1,重新指向API头第一字节
                    SetThreadContext(hThread, &ct);
                    ResumeThread(hThread);
                    CloseHandle(hThread);
                }
                else if(ch == 'N' || ch == 'n')
                {
                    ///不允许执行
                    ct.Esp+= 0x14; ///修正堆栈
                    ct.Eip = pt; ///修正EIP到返回地址
                    SetThreadContext(hThread, &ct);
                    ResumeThread(hThread);
                    CloseHandle(hThread);
                }
                else
                {
                    ///退出
                    ct.Eip--;
                    SetThreadContext(hThread, &ct);
                    WriteProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///还原API头部信息
                    WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL);
                    ResumeThread(hThread);
                    CloseHandle(hThread);
                    yes = FALSE;
                }
            }
            else if((DWORD)dbg.u.Exception.ExceptionRecord.ExceptionAddress == (lpapi + 2)) ///如果是中断在第二条指令
            {
                hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dbg.dwThreadId); ///打开线程
                ct.ContextFlags = CONTEXT_ALL;
                SuspendThread(hThread); ///暂停线程,否则不可以读取线程寄存器信息
                GetThreadContext(hThread, &ct); ///读取线程寄存器信息
                WriteProcessMemory(hProcess, (LPVOID)lpapi, &cc, 1, NULL); ///重新在API第一条指令上设置CC断点
                WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL); ///还原第二条指令
                ct.Eip--; ///修正EIP
                SetThreadContext(hThread, &ct);
                ResumeThread(hThread);
                CloseHandle(hThread);
            }



            ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
        }
        ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
    }
    DebugActiveProcessStop(pid);
    return 0;
}


3.jpg

1.jpg

2.jpg


代码下载:


main.rar (1.96 KB, 下载次数: 18)

评分

参与人数 6HB +4 THX +3 收起 理由
消逝的过去 + 1
zxjzzh + 1 [吾爱汇编论坛52HB.COM]-软件反汇编逆向分析,软件安全必不可少!
禽大师 + 1
agan8888 + 1
a1453917518 + 1 + 1 [快捷评语] - 吃水不忘打井人,给个评分懂感恩!
tianzhiya + 1 吃水不忘打井人,给个评分懂感恩!

查看全部评分

吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
tianzhiya 发表于 2016-8-17 10:43 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
今晚打老虎 发表于 2016-8-17 11:27 | 显示全部楼层

看不懂 好高深
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
酷爱 发表于 2016-8-17 19:53 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
84484884 发表于 2018-12-17 14:33 | 显示全部楼层

这个高明
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
永远 发表于 2021-3-26 08:20 | 显示全部楼层
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
平淡 发表于 2021-7-11 15:44 | 显示全部楼层

这个利用调试来实现感觉有点没必要,如果进程检测调试,整个HOOK就没用了。。。。
吾爱汇编论坛-学破解,防破解!知进攻,懂防守!逆向分析,软件安全!52HB.COM
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

警告:本站严惩灌水回复,尊重自己从尊重他人开始!

1层
2层
3层
4层
5层
6层
7层

免责声明

吾爱汇编(www.52hb.com)所讨论的技术及相关工具仅限用于研究学习,皆在提高软件产品的安全性,严禁用于不良动机。任何个人、团体、组织不得将其用于非法目的,否则,一切后果自行承担。吾爱汇编不承担任何因为技术滥用所产生的连带责任。吾爱汇编内容源于网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除。如有侵权请邮件或微信与我们联系处理。

站长邮箱:SharkHeng@sina.com
站长QQ:1140549900


QQ|RSS|手机版|小黑屋|帮助|吾爱汇编 ( 京公网安备11011502005403号 , 京ICP备20003498号-6 )|网站地图

Powered by Discuz!

吾爱汇编 www.52hb.com

快速回复 返回顶部 返回列表