逆向工程师检测递归调用的经验

逆向工程 艾达 混淆 去混淆 职能
2021-06-20 14:11:13

我完全没有反转现实世界二进制代码的经验,所以我想知道混淆的代码是如何防止逆向的。我怀疑逆向总是能找到一些方法来理解隐藏在里面的东西,即使对于重度混淆的代码,但我不知道他们是怎么想的。

这部分来自于检测递归调用的这个问题,其中两个答案都给出了一个静态方法:递归地查看原始函数调用的函数是否被重新调用。

以某种理论上的方式,如果程序员使用延续传递风格,则可以绕过这种方法,这是因为没有更明确的

call myself

代码里面。我已经实施了以下程序来测试这个想法:

template<typename T> 
auto obf_if(bool p, T a, T b) -> T
{
  T* pts[4] = { &a, &b, &a + 1, &b + 1 };
  return *pts[int{ p }];
}

template<typename T>
auto obf_cmp(T a, T b) -> int
{
  return obf_if<int>(a == b, 0, obf_if<int>(a < b, -1, 1));
}

using obf_strcmp_t = std::function < int(char*, char*) >;

auto h_strcmp(obf_strcmp_t func, char* str1, char* str2) -> int
{
  return obf_if<int>((*str1 == *str2) && (*str1 != 0), 
                     func(str1 + 1, str2 + 1), obf_cmp<int>(*str1, *str2));
}
using h_strcmp_t = decltype(h_strcmp);

obf_strcmp_t y_strcmp(h_strcmp_t func)
{
  return std::bind(func, std::bind(y_strcmp, func), 
                   std::placeholders::_1, std::placeholders::_2);
}

int main(int argc, char* argv[]) 
{
  char str1[] = "ab"; 
  char str2[] = "ac";
  return y_strcmp(h_strcmp)(str1, str2);
}

这是strcmp使用y 组合器的一个简单实现但是这段代码导致实现内部没有更多的直接调用(甚至没有条件跳转),除了第一个

y_strcmp(h_strcmp)(str1, str2)

作为一个业余爱好者,我什至在 IDA 中加载了二进制代码(由 VS2013 编译),看到调用被替换为

 call edx

然而,因为我写了它,我知道如何检测这一点(例如,通过跟踪传递给函数的参数来检测隐式递归调用,edx 的值只能是传递的参数之一),我认为反向器也是如此。所以我的问题是:

假设你不知道这个技巧,它会妨碍你理解二进制代码吗?

NB因为ws已经暗示这个问题只是一个基于意见的问题,所以它迟早会被关闭,但是如果有人提供想法我非常感谢。

1个回答

钩住您担心的所有函数的开头可能会使用 EasyHook 递归。让您的挂钩函数在线程本地存储中记录函数地址(以避免同步问题),然后查看完整的堆栈回溯或仅查看调用函数。递归函数将是显而易见的。