在 IDA 生成的反编译代码中,我看到如下表达式:
malloc(20 * c | -(20 * (unsigned __int64)(unsigned int)c >> 32 != 0))
malloc(6 * n | -(3 * (unsigned __int64)(unsigned int)(2 * n) >> 32 != 0))
有人可以解释这些计算的目的吗?
c 和 n 是 int(有符号整数)值。
更新。
原始 C++ 代码是用 MSVC 为 32 位平台编译的。
下面是上面反编译后的第二行C代码的汇编代码(malloc(6 * ..)):
mov ecx, [ebp+pThis]
mov [ecx+4], eax
mov eax, [ebp+pThis]
mov eax, [eax]
shl eax, 1
xor ecx, ecx
mov edx, 3
mul edx
seto cl
neg ecx
or ecx, eax
mov esi, esp
push ecx ; Size
call dword ptr ds:__imp__malloc
最佳答案
我猜测原始源代码使用 C++ new
运算符分配数组并使用 Visual C++ 编译。由于 user3528438 的回答表明此代码旨在防止溢出。具体来说,它是一个 32 位无符号饱和乘法。如果乘法的结果大于 4,294,967,295,即 32 位无符号数的最大值,则结果被限制或“饱和”到该最大值。
自 Visual Studio 2005 以来,Microsoft 的 C++ 编译器具有 generated code to protect against overflows .例如,我可以通过使用 Visual C++ 编译以下代码来生成可以反编译到您的示例中的汇编代码:
#include <stdlib.h>
void *
operator new[](size_t n) {
return malloc(n);
}
struct S {
char a[20];
};
struct T {
char a[6];
};
void
foo(int n, S **s, T **t) {
*s = new S[n];
*t = new T[n * 2];
}
其中,使用 Visual Studio 2015 的编译器生成以下汇编代码:
mov esi, DWORD PTR _n$[esp]
xor ecx, ecx
mov eax, esi
mov edx, 20 ; 00000014H
mul edx
seto cl
neg ecx
or ecx, eax
push ecx
call _malloc
mov ecx, DWORD PTR _s$[esp+4]
; Line 19
mov edx, 6
mov DWORD PTR [ecx], eax
xor ecx, ecx
lea eax, DWORD PTR [esi+esi]
mul edx
seto cl
neg ecx
or ecx, eax
push ecx
call _malloc
大多数反编译表达式实际上只用于处理一条汇编语句。如果前面的 MUL 指令溢出,汇编指令 seto cl
将 CL 设置为 1,否则将 CL 设置为 0。类似地,表达式 20 * (unsigned __int64)(unsigned int)c >> 32如果
计算结果为 1,否则计算结果为 0。20 * c
的结果溢出,!= 0
如果不存在这种溢出保护并且 20 * c
的结果确实溢出,那么对 malloc
的调用可能会成功,但分配的内存比计划的目的。然后程序可能会写入实际分配的内存末尾并丢弃其他内存位。这相当于缓冲区溢出,可能会被黑客利用。
关于c++ - 有人可以解释 malloc(20 * c | -(20 * (unsigned __int64)(unsigned int)c >> 32 != 0)) 的含义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34442943/