2

我不知道原始代码,但我不相信右移和 abs 会这么复杂。

这是重命名的反编译 IDA PRO 代码的样子

char Ship; //Could be 0-7 (8 is reversed for special purpose)
char NewShip = 1; //Could be 0-7  (8 is reversed for special purpose)
short Frequency = 0; //This could be from 0 to 9999
bool NumberToFrequency = true;

Frequency = GetNextFrequencyToJoin(player->MyArena);
if ( NumberToFrequency )
{ //TODO: maybe the below is just Frequency % 7; ?
  NewShip = (((unsigned long)Frequency >> 32) ^ abs(Frequency) & 7) - ((unsigned long)Frequency >> 32);
  Ship = NewShip;
} else {
  Ship = NewShip;
}

这是一个 IDEOne 测试http://ideone.com/Q2bEjU

似乎NewShip = abs(frequency) & 7);是我真正需要的一切似乎我通过循环测试了所有可能性,它永远不会搞砸。

另一个反编译器给了我这个结果

 asm("cdq ");
 NewShip = ((Var1 ^ Var2) - Var2 & 7 ^ Var2) - Var2;

哪个没有右移或任何东西对我来说仍然看起来很陌生,可能显示了绝对数字是如何工作的,但仍然不知道右移 32 的来源。

假设NumberToFrequency要做的是使频率与船舶相同,但当然频率超过 7,因此剩余值仍应转换为船舶值,因此我假设它只是%7 的模数。

但是为什么这么复杂的代码可能意味着完全不同的东西呢?我只是问代码是什么意思。我将在下面添加汇编代码。我什至在下面的程序集中找不到 Shift right 32 我很确定它在同一个地方。

.text:0040DD3A                 mov     ecx, [ebp+1Ch]  ; arena
.text:0040DD3D                 call    GetNextFrequencyToJoin
.text:0040DD42                 mov     ecx, [ebp+1Ch]
.text:0040DD45                 mov     si, ax
.text:0040DD48                 mov     [esp+220h+var_20C], si
.text:0040DD4D                 cmp     [ecx+1ACCEh], ebx
.text:0040DD53                 jz      short loc_40DD98
.text:0040DD55                 movsx   eax, si
.text:0040DD58                 cdq
.text:0040DD59                 xor     eax, edx
.text:0040DD5B                 sub     eax, edx
.text:0040DD5D                 and     eax, 7
.text:0040DD60                 xor     eax, edx
.text:0040DD62                 sub     eax, edx
.text:0040DD64                 mov     [esp+220h+var_20F], al

编辑:我自己找到了答案,似乎那些 shift 32>> 32是为一些旧的 C 编译支持添加的无用垃圾,其类型匹配 32 位 DWORD 或类似的废话。

4

2 回答 2

5

轮班并不是没有用的。这是 Hexray 在其 c 反汇编中无法重现的一种无组逻辑形式。

.text:0040DD55                 movsx   eax, si
.text:0040DD58                 cdq
.text:0040DD59                 xor     eax, edx
.text:0040DD5B                 sub     eax, edx
.text:0040DD5D                 and     eax, 7
.text:0040DD60                 xor     eax, edx
.text:0040DD62                 sub     eax, edx

是显码。EDX:EAX是 的符号扩展版本SI,因此EDX是 0 或 -1。xor要么保持eax不变或反转它,要么保持不变,要么加sub一,依此类推:

if (si < 0) {
    eax = ~si;
    eax += 1;
    eax &= 0x7;
    eax = ~eax;
    eax += 1;
} else {
    eax = si & 0x7;
}

第一个分支仍然可以简化,但我把它留给你......


更新

分支仅不同之处si<0已经暗示了正在发生的事情。该序列eax = ~si; eax += 1;可以理解为二进制补码,因此插入我们对这个补码的知识,我们得到

if (si < 0) {
    eax = -1 * si;
    eax &= 0x7;
    eax *= -1;
} else {
    eax = si & 0x7;
}

或简而言之

eax = (abs(si) & 0x7) * sign(si);

或使用带符号的模数运算符

al = si % 8;
于 2014-04-26T11:55:45.917 回答
0

我想我明白了,我使用 IDA-PRO 的反编译器似乎在所有地方都生成了这些 Shift right 32 >> 32,在我看到这个函数的所有情况下,abs()它看起来就像是绝对数字函数的无用包装器。

我找到的一些例子。

//1
((((unsigned long)i >> 32) ^ abs(i)) - ((unsigned long)i >> 32))
//2
(((unsigned long)encryption->field_25E >> 32) ^ abs(encryption->field_25E)) - ((unsigned long)encryption->field_25E >> 32);
//3
((((unsigned long)i >> 32) ^ abs(i)) - ((unsigned long)i >> 32))
//4
(((unsigned long)(v104->field_A8 + 1) >> 32) ^ abs(*((unsigned char*)&(v104->field_A8)) + 1) & 7) - ((unsigned long)(v104->field_A8 + 1) >> 32);
//5
(((unsigned long)v11 >> 32) ^ abs(v11)) - ((unsigned long)v11 >> 32);
//6
(((unsigned long)v4->field_262 >> 32) ^ abs(v4->field_262)) - ((unsigned long)v4->field_262 >> 32)
//7
(((unsigned long)v18 >> 32) ^ abs(v18)) - ((unsigned long)v18 >> 32);
//8 (not refactored yet).
((((unsigned long)*(unsigned int *)(v1 + 610) >> 32) ^ abs(*(unsigned int *)(v1 + 610))) - ((unsigned long)*(unsigned int *)(v1 + 610) >> 32)

您可能还会>> 32在另外 1 个地方看到这些,我已经知道这些只是优化的研究部门,看起来更加不同。

像这样疯狂的事情(我用我的正则表达式工具解决了这个问题)

(signed int)((unsigned int)v130 + ((unsigned long)(18446744071705233545i64 * (signed int)v130) >> 32)) >> 5;

//Originally it looked something like this
LODWORD(v202) = (signed int)((_DWORD)v202 + (0xFFFFFFFF88888889ui64 * (signed int)v202 >> 32)) >> 5;

//Or without the hexadecimal values
LODWORD(v202) = (signed int)((_DWORD)v202 + ((unsigned __int64)(18446744071705233545i64 * (signed int)v202) >> 32)) >> 5;

//You will see it getting used like this
(signed int)(((unsigned int)v202 >> 31) + v202)

But what it really means is
v202 / 60

用于将其转换回的方程式在http://www.hexblog.com/?p=17/ 60上进行了讨论

于 2014-04-26T11:42:15.093 回答