如何简化32 Xor绝对数和值的装配平移右移

时间:2014-04-26 10:57:36

标签: assembly xor shift absolute-value ida

我不知道原始代码,但我不相信这是右移和绝对的复杂。

重命名的反编译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,所以其余值仍应转换为船舶值,因此我认为它只是一个模数{{1 7。

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

%

编辑: 我发现自己的答案似乎是转移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 是无用的垃圾添加到一些旧的C编译支持类型匹配32位DWORD或类似的垃圾。

2 个答案:

答案 0 :(得分:5)

这些转变并非毫无用处。这是Hexray无法在其反汇编中重现的一种无法解释的逻辑形式。

.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:EAXSI的符号扩展版本,因此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;可以理解为two's-complement,因此插入我们对此补充的知识

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

或简而言之

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

或使用有符号模数运算符

al = si % 8;

答案 1 :(得分:0)

我想我弄清楚了,我使用IDA-PRO的反编译器似乎在整个地方生成了这些Shift右边的>> 32,并且在所有情况下,我看到{{1}使用函数它似乎是绝对数字函数的无用包装。

我找到的一些例子。

abs()

您可能还会在另外1个地方看到这些//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

http://www.hexblog.com/?p=17上讨论了用于将其转换回(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 的公式