c++ - 有人可以解释 malloc(20 * c | -(20 * (unsigned __int64)(unsigned int)c >> 32 != 0)) 的含义

标签 c++ c assembly

在 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如果 20 * c 的结果溢出,!= 0 计算结果为 1,否则计算结果为 0。

如果不存在这种溢出保护并且 20 * c 的结果确实溢出,那么对 malloc 的调用可能会成功,但分配的内存比计划的目的。然后程序可能会写入实际分配的内存末尾并丢弃其他内存位。这相当于缓冲区溢出,可能会被黑客利用。

关于c++ - 有人可以解释 malloc(20 * c | -(20 * (unsigned __int64)(unsigned int)c >> 32 != 0)) 的含义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34442943/

相关文章:

c - Microsoft 编译器和 GNU 编译器在输出可执行文件大小方面的差异

math - 有人可以解释一下汇编中多精度乘法的过程吗?

使用 cmake 和 pybind11 构建示例应用程序时找不到 Python.h

c++ - 是否有初始化列表的替代方法?

c++ - 非顺序整数 C++ 枚举的最佳方法是什么

c++ - 试图拒绝负数并让人们选择另一个但它完成了

你能用 C#define 注释吗?

c - 在 c 中未初始化时 int 的默认值。为什么我得到不同的输出?

assembly - ARM中如何获取寄存器值的二进制补码?

ios - 方法调配不适用于 iOS 10.1