HexRays - 什么是“__OFSUB__()”目的?
HexRays - what is "__OFSUB__()" purpose?
在以下使用 Ida pro 的 Hex rays 的反编译函数中:
int sub_409650()
{
int v0; // ecx@1
int result; // eax@1
bool v2; // zf@1
bool v3; // sf@1
unsigned __int8 v4; // of@1
unsigned __int16 v5; // cx@2
unsigned int v6; // ecx@2
v0 = gS1_dword_62EEA8 & 7;
result = gS1_dword_62EEA8 - v0;
v4 = __OFSUB__(gS1_dword_62EEA8 - v0, 16);
v2 = gS1_dword_62EEA8 - v0 == 16;
v3 = gS1_dword_62EEA8 - v0 - 16 < 0;
gS1_dword_62EEA8 -= v0;
gs2_dword_62EFB4 >>= v0;
if ( (unsigned __int8)(v3 ^ v4) | v2 )
{
v5 = *dword_62EFB0;
++dword_62EFB0;
v6 = (v5 << result) | gs2_dword_62EFB4;
result += 16;
gs2_dword_62EFB4 = v6;
gS1_dword_62EEA8 = result;
}
return result;
}
它调用 __OFSUB__
但它有什么作用?我认为这与溢出有关 - 但如果那是真的那么为什么不是条件:
// Checking if subtracting v0 is 16 or negative?
if ( v3 | v2 )
更新:raw asm 是(现在重命名了一些东西):
.text:00409650 sub_409650 proc near
.text:00409650 mov eax, gBitCounter_62EEA8
.text:00409655 push esi
.text:00409656 mov esi, gFirstAudioFrameDWORD_dword_62EFB4
.text:0040965C mov ecx, eax
.text:0040965E and ecx, 7
.text:00409661 shr esi, cl
.text:00409663 sub eax, ecx
.text:00409665 cmp eax, 10h
.text:00409668 mov gBitCounter_62EEA8, eax
.text:0040966D mov gFirstAudioFrameDWORD_dword_62EFB4, esi
.text:00409673 jg short loc_4096A5
.text:00409675 mov edx, gAudioFrameDataPtr
.text:0040967B xor ecx, ecx
.text:0040967D mov cx, [edx]
.text:00409680 add edx, 2
.text:00409683 mov esi, ecx
.text:00409685 mov ecx, eax
.text:00409687 shl esi, cl
.text:00409689 mov ecx, gFirstAudioFrameDWORD_dword_62EFB4
.text:0040968F mov gAudioFrameDataPtr, edx
.text:00409695 or ecx, esi
.text:00409697 add eax, 10h
.text:0040969A mov gFirstAudioFrameDWORD_dword_62EFB4, ecx
.text:004096A0 mov gBitCounter_62EEA8, eax
.text:004096A5
.text:004096A5 loc_4096A5: ; CODE XREF: sub_409650+23j
.text:004096A5 pop esi
.text:004096A6 retn
.text:004096A6 sub_409650 endp
没什么好说的。 HexRays 将此函数反编译为可读的东西做得很糟糕,但它没有出错。
给定程序集的快速分析:
mov eax, gBitCounter_62EEA8 ; eax = gBitCounter_62EEA8
push esi
mov esi, gFirstAudioFrameDWORD_dword_62EFB4 ; esi = gFirstAudioFrameDWORD_dword_62EFB4
mov ecx, eax
and ecx, 7
; esi = gFirstAudioFrameDWORD_dword_62EFB4 >> (gBitCounter_62EEA8 & 7)
; i.e, esi got shiftted by the 3 LSB's of gBitCounter_62EEA8
shr esi, cl
; eax = gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7)
sub eax, ecx
cmp eax, 10h
; gBitCounter_62EEA8 -= gBitCounter_62EEA8 & 7
mov gBitCounter_62EEA8, eax
; gFirstAudioFrameDWORD_dword_62EFB4 >>= gBitCounter_62EEA8 & 7
mov gFirstAudioFrameDWORD_dword_62EFB4, esi
; if gBitCounter_62EEA8 > 0x10 { return; }
jg short loc_4096A5
; else... continue work
....
loc_4096A5: ; CODE XREF: sub_409650+23j
pop esi
retn
更好的反编译应该是:
gBitCounter_62EEA8 -= gBitCounter_62EEA8 & 7
gFirstAudioFrameDWORD_dword_62EFB4 >>= gBitCounter_62EEA8 & 7
if (gBitCounter_62EEA8 > 0x10)
{
return;
}
else
{
// rest of code
}
但是,您可能会注意到 HexRays 逆转了这种情况。它产生了这个条件:
if ( (unsigned __int8)(
(gBitCounter_62EEA8 - 16 < 0) ^
(__OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16))) // when this is actually the gBitCounter_62EEA8 var before modifications
|
(gBitCounter_62EEA8 == 16) )
根据 Intel's reference,如果 ZF = 0 and SF = OF
.
则采用 jg
条件很接近:
- 或者
Counter == 16
- 意思是 ZF = 0
所以 jg
没有被采用
或者Counter < 16 XOR __OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16)
,意思是:
Counter < 16
(我们称它为 A)- 意思是 SF=1
__OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16)
(假设是B)表示OF=1
如果A=true
和B=false
表示SF=1,OF=0 => SF!=OF
。如果A=false
和B=true
表示SF=0,OF=1 = > SF!=OF
,表示如果A^B
则SF!=OF
,表示如果A^B => jg not taken
.
]
而且一般来说,如果jg
不被取走,那么"rest of code"就会被执行。
我希望这有助于您理解 HexRays 的行为。它的反编译是正确的但非常多余(它没有清除它可以清除的大量垃圾)并且它无法预测确定条件的适当方法(它采用了更多 "difficult" 路径)
在以下使用 Ida pro 的 Hex rays 的反编译函数中:
int sub_409650()
{
int v0; // ecx@1
int result; // eax@1
bool v2; // zf@1
bool v3; // sf@1
unsigned __int8 v4; // of@1
unsigned __int16 v5; // cx@2
unsigned int v6; // ecx@2
v0 = gS1_dword_62EEA8 & 7;
result = gS1_dword_62EEA8 - v0;
v4 = __OFSUB__(gS1_dword_62EEA8 - v0, 16);
v2 = gS1_dword_62EEA8 - v0 == 16;
v3 = gS1_dword_62EEA8 - v0 - 16 < 0;
gS1_dword_62EEA8 -= v0;
gs2_dword_62EFB4 >>= v0;
if ( (unsigned __int8)(v3 ^ v4) | v2 )
{
v5 = *dword_62EFB0;
++dword_62EFB0;
v6 = (v5 << result) | gs2_dword_62EFB4;
result += 16;
gs2_dword_62EFB4 = v6;
gS1_dword_62EEA8 = result;
}
return result;
}
它调用 __OFSUB__
但它有什么作用?我认为这与溢出有关 - 但如果那是真的那么为什么不是条件:
// Checking if subtracting v0 is 16 or negative?
if ( v3 | v2 )
更新:raw asm 是(现在重命名了一些东西):
.text:00409650 sub_409650 proc near
.text:00409650 mov eax, gBitCounter_62EEA8
.text:00409655 push esi
.text:00409656 mov esi, gFirstAudioFrameDWORD_dword_62EFB4
.text:0040965C mov ecx, eax
.text:0040965E and ecx, 7
.text:00409661 shr esi, cl
.text:00409663 sub eax, ecx
.text:00409665 cmp eax, 10h
.text:00409668 mov gBitCounter_62EEA8, eax
.text:0040966D mov gFirstAudioFrameDWORD_dword_62EFB4, esi
.text:00409673 jg short loc_4096A5
.text:00409675 mov edx, gAudioFrameDataPtr
.text:0040967B xor ecx, ecx
.text:0040967D mov cx, [edx]
.text:00409680 add edx, 2
.text:00409683 mov esi, ecx
.text:00409685 mov ecx, eax
.text:00409687 shl esi, cl
.text:00409689 mov ecx, gFirstAudioFrameDWORD_dword_62EFB4
.text:0040968F mov gAudioFrameDataPtr, edx
.text:00409695 or ecx, esi
.text:00409697 add eax, 10h
.text:0040969A mov gFirstAudioFrameDWORD_dword_62EFB4, ecx
.text:004096A0 mov gBitCounter_62EEA8, eax
.text:004096A5
.text:004096A5 loc_4096A5: ; CODE XREF: sub_409650+23j
.text:004096A5 pop esi
.text:004096A6 retn
.text:004096A6 sub_409650 endp
没什么好说的。 HexRays 将此函数反编译为可读的东西做得很糟糕,但它没有出错。
给定程序集的快速分析:
mov eax, gBitCounter_62EEA8 ; eax = gBitCounter_62EEA8
push esi
mov esi, gFirstAudioFrameDWORD_dword_62EFB4 ; esi = gFirstAudioFrameDWORD_dword_62EFB4
mov ecx, eax
and ecx, 7
; esi = gFirstAudioFrameDWORD_dword_62EFB4 >> (gBitCounter_62EEA8 & 7)
; i.e, esi got shiftted by the 3 LSB's of gBitCounter_62EEA8
shr esi, cl
; eax = gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7)
sub eax, ecx
cmp eax, 10h
; gBitCounter_62EEA8 -= gBitCounter_62EEA8 & 7
mov gBitCounter_62EEA8, eax
; gFirstAudioFrameDWORD_dword_62EFB4 >>= gBitCounter_62EEA8 & 7
mov gFirstAudioFrameDWORD_dword_62EFB4, esi
; if gBitCounter_62EEA8 > 0x10 { return; }
jg short loc_4096A5
; else... continue work
....
loc_4096A5: ; CODE XREF: sub_409650+23j
pop esi
retn
更好的反编译应该是:
gBitCounter_62EEA8 -= gBitCounter_62EEA8 & 7
gFirstAudioFrameDWORD_dword_62EFB4 >>= gBitCounter_62EEA8 & 7
if (gBitCounter_62EEA8 > 0x10)
{
return;
}
else
{
// rest of code
}
但是,您可能会注意到 HexRays 逆转了这种情况。它产生了这个条件:
if ( (unsigned __int8)(
(gBitCounter_62EEA8 - 16 < 0) ^
(__OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16))) // when this is actually the gBitCounter_62EEA8 var before modifications
|
(gBitCounter_62EEA8 == 16) )
根据 Intel's reference,如果 ZF = 0 and SF = OF
.
jg
条件很接近:
- 或者
Counter == 16
- 意思是ZF = 0
所以jg
没有被采用 或者
Counter < 16 XOR __OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16)
,意思是:Counter < 16
(我们称它为 A)- 意思是SF=1
__OFSUB__(gBitCounter_62EEA8 - (gBitCounter_62EEA8 & 7), 16)
(假设是B)表示OF=1
如果
]A=true
和B=false
表示SF=1,OF=0 => SF!=OF
。如果A=false
和B=true
表示SF=0,OF=1 = > SF!=OF
,表示如果A^B
则SF!=OF
,表示如果A^B => jg not taken
.
而且一般来说,如果jg
不被取走,那么"rest of code"就会被执行。
我希望这有助于您理解 HexRays 的行为。它的反编译是正确的但非常多余(它没有清除它可以清除的大量垃圾)并且它无法预测确定条件的适当方法(它采用了更多 "difficult" 路径)