C++ 检测函数是否被 Hook (32 位机器)

标签 c++ security memory byte

当人们 Hook 一个函数时,他们通常会用分支指令修改他们想要 Hook 的函数的前几条指令到他们想做一些事情的地方,然后分支回到原来的函数并恢复它,问题在于从字面上看,没有什么是安全的。您试图隐藏的任何值都可以很容易地找到(这些值可以通过许多其他方式找到,而不仅仅是函数 Hook ,但这就是我在这个问题中关注的全部内容)

假设您在 C++ 应用程序中实现了像 MD5 这样的哈希算法(我没有,这只是问题的一个示例),只是为了这个示例假设您有一个 MD5 函数像这样

void GENERATEMD5(const char *plain, char *out);

你会这样调用它

char hashResult[33] = { 0 };//32 + 1 because of null terminator
GENERATEMD5(passwordInputBuffer, hashResult);
memset(passwordInputBuffer, 0, 32);//set password buf back to null

任何人都可以轻松地 Hook 此 GERERATEMD5() 函数,并在传递给该函数时简单地打印出参数。示例

void md5FuncHook(const char *plain, char *out)
{
    md5Hook(plain, out);

    console::print("Plain: %s - Hash: %s", plain, out);
}

我在考虑这个问题,但我只能想出一种方法来检测一个函数是否被 Hook (假设他们通过修改函数的前几条指令来 Hook 该函数)。那将是检查函数的前几个字节,然后确认它们是它们应该是的。 例如,如果我们知道函数 GERERATEMD5() 的前几个字节是

int GERERATEMD5_Function_bytes_0 = 0x12341234;//just random bytes for the example
int GERERATEMD5_Function_bytes_1 = 0x12341234;//just random bytes for the example
int GERERATEMD5_Function_bytes_2 = 0x12341234;//just random bytes for the example
int GERERATEMD5_Function_bytes_3 = 0x12341234;//just random bytes for the example

然后我们可以做这样的事情

void checkIfGENERATEMD5HasBeenHooked()
{
    int GERERATEMD5_Function_bytes_0 = 0x12341234;//just random bytes for the example
    int GERERATEMD5_Function_bytes_1 = 0x12341234;//just random bytes for the example
    int GERERATEMD5_Function_bytes_2 = 0x12341234;//just random bytes for the example
    int GERERATEMD5_Function_bytes_3 = 0x12341234;//just random bytes for the example

    int readGENERATEMD5FunctionBytes0, readGENERATEMD5FunctionBytes1, readGENERATEMD5FunctionBytes2, readGENERATEMD5FunctionBytes3;
    memcpy(&readGENERATEMD5FunctionBytes0, (char *)(&GENERATEMD5 + 0x00), 0x04);
    memcpy(&readGENERATEMD5FunctionBytes1, (char *)(&GENERATEMD5 + 0x04), 0x04);
    memcpy(&readGENERATEMD5FunctionBytes2, (char *)(&GENERATEMD5 + 0x08), 0x04);
    memcpy(&readGENERATEMD5FunctionBytes3, (char *)(&GENERATEMD5 + 0x0C), 0x04);

    if(GERERATEMD5_Function_bytes_0 == readGENERATEMD5FunctionBytes0 && GENERATEMD5_Function_bytes_1 == readGENERATEMD5FunctionBytes1 && GENERATEMD5_Function_bytes_2 == readGENERATEMD5FunctionBytes2 && GENERATEMD5_Function_bytes_3 == readGENERATEMD5FunctionBytes3)
    {
        //our GENERATEMD5() function is clean
    }
    else
    {
        //hook detected or some other form of function modification detected
    }
}

但是我尝试过的所有方法似乎都行不通。我假设的问题来自于我读取函数本身字节的位置,例如对 memcpy 的调用实际上并未读取位于 &GENERATEMD5 + OFFSET 的字节。我只是做错了什么吗?还是有更好/不同的方式来做我想完成的事情? (顺便说一句,是的,我知道攻击者在 Hook 您的函数时可能会使用许多其他 Hook 方法,除了我上面描述的方法之外,还有许多其他方法可以从您的可执行文件中获取您的敏感信息,但这个问题有与这些无关,所以请只关注问题,而不是仅仅说“这样做毫无意义”或“有简单的方法可以绕过它”等...)

最佳答案

我已经做到了。问题是加载程序会在重定位期间修改代码,因此您不能依赖操作数字段每次都是相同的值。在我的例子中,我使用了反汇编库并仅对操作码字节进行了哈希处理。我使用 BASTARD 在运行时进行反汇编,但该项目早就死了。我认为现在有更好的选择。

原则上,您可能会以不会发生重定位修正的方式编写目标函数,但这会带来更多的麻烦,而不是值得的。

关于C++ 检测函数是否被 Hook (32 位机器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49277363/

相关文章:

c++ - 在工作线程完成 MFC 时禁用控制变量

c++ - 创建一个模板,该模板是具有多个变量的自定义数据类型的 vector

java - Java ReDos 易受攻击吗?

javascript - JSON 解析 - 内存依赖?

Java内存管理对象与原始类型

c++ - 在应用程序文件夹中为 C/C++ 安装库 "IGRAPH"

c++ - 等待服务启动/停止

java - Tomcat 连接器匹配属性警告

php - 用于登录信息和关键任务信息的独立数据库?

c++ - 构造函数调用了已创建的对象