吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 19112|回复: 63
收起左侧

[原创] Inline hook DLL思路讨论

  [复制链接]
chomosuke 发表于 2019-12-17 06:56
本帖最后由 chomosuke 于 2020-4-23 19:08 编辑

声明:以下资料仅供交流学习,严禁将以下内容用于商业或者非法用途,否则一切后果用户自负


以下为不完整的C++ DLL伪代码,仅供交流学习:
Inline hook可以用于程序侦错用途,因法律问题请只用于侦错自己开发的软件

[C++] 纯文本查看 复制代码
#include "pch.h"

// 出处:http://www.cplusplus.com/forum/general/202725/#msg964447
std::vector<const void*> scan_memory(void* address_low, const std::size_t& nbytes, const std::vector<BYTE>& bytes_to_find) {
        std::vector<const void*> addresses_found;

        // all readable pages: adjust this as required
        const DWORD pmask{ PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY };
        ::MEMORY_BASIC_INFORMATION mbi{};

        BYTE* address{ static_cast<BYTE*>(address_low) };
        BYTE* address_high{ address + nbytes };
        while (address < address_high && ::VirtualQuery(address, std::addressof(mbi), sizeof(mbi))) {

                // committed memory, readable, wont raise exception guard page
                //if ((mbi.State == MEM_COMMIT) && (mbi.Protect | pmask) && !(mbi.Protect & PAGE_GUARD)) {
                if ((mbi.State == MEM_COMMIT) && (mbi.Protect & pmask) && !(mbi.Protect & PAGE_GUARD)) {
                        const BYTE* begin{ static_cast<const BYTE*>(mbi.BaseAddress) };
                        const BYTE* end{ begin + mbi.RegionSize };

                        const BYTE* found{ std::search(begin, end, bytes_to_find.begin(), bytes_to_find.end()) };
                        while (found != end) {
                                addresses_found.push_back(found);
                                found = std::search(found + 1, end, bytes_to_find.begin(), bytes_to_find.end());
                        }
                }

                address += mbi.RegionSize;
                mbi = {};
        }

        return addresses_found;
}

std::vector<const void*> scan_memory(const std::vector<BYTE>& bytes_to_find) {
        auto base{ ::GetModuleHandleW(NULL) }; // NULL为本体exe,如有需要可以参考出处写法,理论上可以查找其他dll或exe的内存部分
        if (base == nullptr) return {};

        MODULEINFO minfo{};
        ::GetModuleInformation(GetCurrentProcess(), base, std::addressof(minfo), sizeof(minfo));

        return scan_memory(base, minfo.SizeOfImage, bytes_to_find);
}

VOID hook_util(PVOID addressToHook, PVOID functionToInject, UINT length) {
        if (length < 5) return; // 至少要五字元才能放一个JMP

        // 内存读写权限属性
        DWORD original_protection;
        DWORD placeholder;

        // 内存读写提权
        while (VirtualProtect(addressToHook, length, PAGE_EXECUTE_READWRITE, &original_protection) == 0);

        memset(addressToHook, 0x90, length); // 多余指令设定为无效果的NOP,减少运行出错机会

        // 于指定addressToHook位置放置JMP运算元
        *reinterpret_cast<BYTE*>(addressToHook) = 0xE9;
        // 于指定addressToHook位置放置JMP运算子
        *reinterpret_cast<DWORD_PTR*>(reinterpret_cast<DWORD_PTR>(addressToHook) + 1) = reinterpret_cast<DWORD_PTR>(functionToInject) - reinterpret_cast<DWORD_PTR>(addressToHook) - 5;

        // 内存读写降权
        while (VirtualProtect(addressToHook, length, original_protection, &placeholder) == 0);
}

/* 
        结构体例子:
        FFFFFF00 80C30000  00CE0000 00010000
        00F00FF0 12F0EC12
        
        提示:注意位元組順序!
        dumpSize为0x100 (256字元)
        dumpBuffer为0x12ECF012
*/
struct myStruct {
        UINT32 padding_0; // 4字元填充(unsigned int 32-bit = 32/8->4字元),用于对位
        UINT64 padding_1; // 8字元填充
        DWORD dumpSize;
        UINT32 padding_2; // 4字元填充
        LPCVOID dumpBuffer;
};

myStruct* param;
DWORD_PTR param_reference;
std::wstring my_string;

VOID myFunc() {
        if (!param) return; // 空指针检测

        HANDLE& myHandle{ reinterpret_cast<HANDLE&>(param_reference) }; // 直接还原HANDLE reference / 引用

        // 调用param里的参数,写入文件?(WriteFile)
        if (!param->dumpBuffer) return;
        if (param->dumpSize <= 0) return;
}

DWORD_PTR original_func;

/*
        _asm部分解释:
        先保存原有寄存器跟标志位到堆栈,运行你的代码后还原(push/pop ad/fd)
        mov会拷贝eax到param值中,以防止后面的void myFunc()意外改动
        对于有些x86汇编禁止mov的操作,可以先推进堆栈再立即推出
        call会调用你写的void myFunc()
        然后可以在void myFunc()里调用param(原有eax)的数值、指针或引用
        最后的jmp跳回原来的程序位置,继续运行
*/
VOID __declspec(naked) wrapper() {
        _asm {
                /* 这里补上原本有的指令 */
                pushad
                pushfd
                mov param, eax
                push dword ptr ss : [ecx + 0x30]
                pop param_reference
                push dword ptr ss : [eax + 0x60]
                pop my_string
                call dword ptr[myFunc]
                popfd
                popad
                /* 或者这里补上原本有的指令 */
                jmp dword ptr[original_func]
        }
}

VOID hook() {
        const std::vector<BYTE> hook_signature{ 0x6A, 0x00, 0x50, 0x10, 0xFF, 0x75, 0x0C, 0xFF, 0x08 }; // 需要hook的特征码
        const DWORD_PTR hook_address{ reinterpret_cast<DWORD_PTR>(scan_memory(hook_signature).at(0)) }; // 需要hook的特征码位置,.at(0)会提取第一个记录
        const UINT hook_length{ 0x5 }; // 必须是一个或者几个完整的指令的长度,至少要5字元才能放1个jmp,并在_asm部分补上此处被覆盖的指令。

        original_func = hook_address + hook_length;

        hook_util(reinterpret_cast<PVOID>(hook_address), wrapper, hook_length);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
        switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH:
                hook(); // 载入dll时hook
                break;
        case DLL_PROCESS_DETACH:
                break;
        }
        return TRUE;
}



免费评分

参与人数 29威望 +1 吾爱币 +29 热心值 +29 收起 理由
hongshen233 + 1 + 1 热心回复!
拾壹的理智 + 1 + 1 我很赞同!
行星波动 + 1 + 1 谢谢@Thanks!
RyanLi + 1 + 1 那个参赛作品还有链接吗?
抱歉、 + 1 用心讨论,共获提升!
wangxp + 1 + 1 谢谢@Thanks!
pudgala + 1 + 1 谢谢@Thanks!
az75 + 1 热心回复!
Hmily + 1 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
wuainiubi + 1 + 1 谢谢@Thanks!
tankui + 1 + 1 我很赞同!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
涛之雨 + 1 + 1 谢谢@Thanks!
shery2010 + 1 谢谢@Thanks!
先LLL + 1 + 1 我很赞同!
gaosld + 1 + 1 谢谢@Thanks!
宇逸 + 1 谢谢@Thanks!
hehehero + 1 + 1 鼓励转贴优秀软件安全工具和文档!
wyc714 + 1 + 1 谢谢@Thanks!
hxw0204 + 1 + 1 热心回复!
DDFer + 1 + 1 我很赞同!
南冥的小鲲 + 1 + 1 我很赞同!
ys1312 + 1 + 1 我很赞同!
MYC18688368548 + 1 + 1 谢谢大公无私
逍遥枷锁 + 1 + 1 我很赞同!
461735945 + 1 + 1 谢谢@Thanks!
ChanCherry + 1 热心回复!
feng645806 + 1 + 1 谢谢@Thanks!
冰骷髅 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Quincy379 发表于 2019-12-17 12:29
谢谢大神分享思路,要会这个还得要学C啊
涛之雨 发表于 2019-12-17 19:23
chomosuke 发表于 2019-12-17 19:20
没事,刚才我又找到了:https://pan.baidu.com/s/1_0poXGET1ktXIypd44FfYA

谢谢

在下载了
fxmmm 发表于 2019-12-17 07:06
ufo2273810 发表于 2019-12-17 07:22
感谢分享思路。
dutyzqly 发表于 2019-12-17 07:52
学习了,感谢分享
szwlkj 发表于 2019-12-17 07:54
好复杂啊  不会
 楼主| chomosuke 发表于 2019-12-17 07:56
szwlkj 发表于 2019-12-17 08:54
好复杂啊  不会

确实很复杂,但某宝会的大佬们都套路太深,小弟看不过去才鼓起勇气教大家的
qq8945051 发表于 2019-12-17 07:57
学习学习   看下。。。
大雄没有小叮当 发表于 2019-12-17 07:58
学习了感谢
bdrdc 发表于 2019-12-17 08:07
这个不错,好好研究研究.......
hu1314 发表于 2019-12-17 08:11

学习了,感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-24 10:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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