我只是使用IDA反向设计二进制文件并加载Hex Ray以检查特定功能。 generate C源代码包含以下if语句:
LP_ret_GlobalLock_1 = GlobalLock(hMem);
LP_ret_GlobalLock_2 = LP_ret_GlobalLock_1;
...
if ( !LP_ret_GlobalLock_1 || (v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0) )
我不确定完全理解以下部分:
(v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0)
v9初始化为v6 + 4;但是后来v6被修改为指针LP_ret_GlobalLock_2,最后v9检查是否小于0.这是正确的吗?在计算v9时,v6使用了什么值? LP_ret_GlobalLock_2或之前的值?
答案 0 :(得分:5)
我猜你问的是comma operator。它在逗号之前计算表达式,然后在逗号之后计算表达式,整个事物的结果是第二个表达式的结果。
首先是v9 = *(_DWORD *)(v6 + 4)
,然后是*(_DWORD *)v6 = LP_ret_GlobalLock_2
,然后是v9 < 0
。在评估了前两个表达式之后,结果是v9 < 0
的结果。
我知道你是通过逆向工程得到的。我永远不会在if语句中使用带有副作用的逗号运算符,就像我自己编写代码一样;它太混淆了。
答案 1 :(得分:3)
就我所见,变量v6
是一个指针。另外,我假设_DWORD
是32位数量。这是细分:
v9 = *(_DWORD *)(v6 + 4)
:v9
被分配给v6
指向的32位字后面的32位字。*(_DWORD *)v6 = LP_ret_GlobalLock_2
:v6
指向的32位字被赋予LP_ret_GlobalLock_2
的值。v9 < 0
:表达式求值为v9 < 0
,即如果v6
指向的32位字后面的32位位字小于零,则为真。如果_DWORD
是无符号值v9
,则永远不会为负值且表达式始终为false。
答案 2 :(得分:2)
如果在C中编译,则表达式从左到右进行计算。因此,在计算v9时,使用v6的初始值。
最终,v9被检查为0,所以你是对的。
简单地说,执行相当于:
v9 = *(_DWORD *)(v6 + 4);
*(_DWORD *)v6 = LP_ret_GlobalLock_2;
return v9 < 0;
但是,我不建议使用您提供的那种复杂的代码,这些代码很难阅读和理解,并且在维护时可能容易出错。将报表扩展为独立报表要好得多。
答案 3 :(得分:2)
理解这句话的作用的关键是逗号运算符。逗号运算符的优先级低于所有其他运算符。它从左到右计算所有子表达式,然后返回最后一个的子表达式。所以,例如,
int a, b;
b = (a=1, a+1);
会将b
设置为2。
所以回答你的问题:
v9
初始化为v6
+ 4;但是v6
被修改为指针LP_ret_GlobalLock_2
,最后v9
检查是否小于0.这是正确的吗?
是
在计算
v9
v6
使用的值时?LP_ret_GlobalLock_2
或之前的值?
之前的值。
答案 4 :(得分:2)
部分
if (v9 = *(_DWORD *)(v6 + 4), *(_DWORD *)v6 = LP_ret_GlobalLock_2, v9 < 0)
的评估就像
一样v9 = *(_DWORD *)(v6 + 4);
*(_DWORD *)v6 = LP_ret_GlobalLock_2;
if (v9 < 0)
/* ... */
任何逗号分隔表达式从左到右计算,表达式的结果是右边部分的结果。与if子句相关的是(v9&lt; 0),在修改v6之前,在第一部分中分配了v9。
答案 5 :(得分:1)
C中的逗号运算符是序列运算符。所以,你的假设是正确的。
但请注意,第二项作业不会改变v6。它改变了v6 [0],即v6指向的值。 v9的分配从v6 [4]读取。