我完全没有反转现实世界二进制代码的经验,所以我想知道混淆的代码是如何防止逆向的。我怀疑逆向总是能找到一些方法来理解隐藏在里面的东西,即使对于重度混淆的代码,但我不知道他们是怎么想的。
这部分来自于检测递归调用的这个问题,其中两个答案都给出了一个静态方法:递归地查看原始函数调用的函数是否被重新调用。
以某种理论上的方式,如果程序员使用延续传递风格,则可以绕过这种方法,这是因为没有更明确的
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已经暗示这个问题只是一个基于意见的问题,所以它迟早会被关闭,但是如果有人提供想法我非常感谢。