加减乘除作为编译器的基础计算方法,在反汇编中应用广泛,其中加法、减法、乘法比较容易,而除法非常困难,尤其底层优化,非常复杂。其中32位和64位编译在这部分非常相似,仅仅是寄存器改变和常数改变,优化方案不变。
加法的反汇编略为简单,仅仅是add、inc指令的使用。
在我们实际的编程中,为了保证代码的逻辑性和可读性,往往会使得代码具有一定的冗余性。
故编译阶段,编译器会采用常量传播和常量折叠两种优化方案,将运行阶段的工作尽可能移到编译阶段去做。
常量传播:编译器将可将已经计算出的结果转化为常量,这样就减少了变量的使用。
常量折叠:编译器将可将已经常量与常量的计算,在编译阶段期间就计算出结果,直接使用。
加法一共三种情况,下面将简单做个实例:
减法也比较简单,仅仅是sub、dec指令的使用。
减法一共三种情况,和加法类似:
乘法在计算的时候会将带有常量的部分优化成lea eax,[eax*a+b]的形式,其中受限于汇编指令的规则,a只能是1/2/4/8,故无法如此处理的乘法计算,还是会以mul/imul进行计算。
mul为无符号乘法,imul为有符号乘法。我们在反汇编的时候可以从此判断变量的类型。
乘法一共有五种情况:
相较于加法、减法和乘法。除法可是复杂太多了。具体正面过程在钱松林老师的《C++反汇编与逆向分析技术揭秘》一书中有详细描述。但是太厚了,我们要把书读薄,我们在这里提炼出骨干和易于记忆的点。
我们使用vs2019 x64的Release版本编译,x64和x86在加减乘除中区别不大。优化方案没有区别。
代码特征:shr
还原方法:C=2^n
代码特征:mul / shr
还原方法:C=2^n/M
代码特征:mul / sub / shr / add / shr
因为是64位编译,多了步移。32位为乘减移加移。
还原方法:C=2^n/(2^32+M)
代码特征:cdq、cqo / and / add / sar
还原方法:C=2^n
代码特征:cdq、cqo / and / add / sar / neg
还原方法:C=-2^n
代码特征:imul / sar / mov / shr / add
还原方法:C=2^n/M
代码特征:imul / add / sar / mov / shr / add
还原方法:C=2^n/M
代码特征:imul / sar / mov / shr / add
乘移移移加-->相乘,右移,移动,右移,相加
还原方法:2^n/(2^32-M)
代码特征:imul / sub / sar / mov / shr / add
乘移移移加-->相乘,相减,右移,移动,右移,相加
还原方法:2^n/(2^32-M)
想要判别除数是多少,根据上面总结的特征就可以很好的判断,通过观察可以轻松得到以下判别法:
1、当简单右移发生的时候,说明是第1种情况【除数为无符号2的幂】。
2、判断是否有cdq、cdo拓展指令,如果有判断是4、5两种情况【除数为有符号2的幂】,还原方法和第一点一致,有neg加负号。
3、判断是imul还是mul,若是mul为一定为无符号乘法,即2、3两种情况【除数为无符号非2的幂】。紧接着判断其行为,若是简单乘移,则为2,还原公式为C=2^n/M;若是乘减移加移,则为3,还原公式为C=2^n/(2^32+M)。
4、判断是imul还是mul,若是imul为一定为有符号乘法,
当MagicNumber>0,无SUB/ADD调整指令时,为情况6;
当MagicNumber<0,有ADD时,为情况7;
当MagicNumber<0,无SUB/ADD调整指令时,为情况8;
当MagicNumber>0,有SUB时,为情况9;
可以这样记忆,除数为负数的两种情况:M为正,有调整指令;M为负,无调整指令。
把有调整指令记作负,即负负得正的规律。一个为负,除数为负。两个为负数,则为正。
若为情况6、7,计算公式为:C=2^n/M;
若为情况8、9,计算公式为:C=2^n/(2^32-M)
F5还原就不说了,在无优化的环境下还原还好,加入流水线等优化,或者无法F5的场景下,F5出来的内容帮助不是很大。
这是使用经验的方法,进行还原的。
总共就三个公式,一个个尝试,选取精度最高的一个。
公式1:C=pow(2,n)
公式2:C=2^n/(2^32+M)
公式3:C=2^n/(2^32-M)
这样可行的理由:因为MagicNumber是由操作系统生成的,精度通常为小数点后九位以上。使用错误的还原方式,还原出的效果差距很大,即使凑巧有和整数很接近的数,比较精度选取精度高的数,就可以还原出正确的除数。当然,这种方法没有被数学证明,可能会有特殊数,不过普适性的优点已经足够引诱我们使用这个方法了。
感兴趣的同学可以写个DEMO测试一下,也可以锻炼写工具的能力。
请不要盲目遵从定式,在玩熟以后多留点心眼。
敌手嵌套内联汇编可能会产生陷阱导致翻译错误。
我在学习这一阶段的时候,对MagicNumber的生成,产生了浓厚的兴趣。很想弄清楚是怎么产生的,但是网上的教程太少了,搜了很多资料还是很少,只能慢慢研究。
根据钱老师的《C++反汇编与逆向分析技术揭秘》中的引导,我找到了对应版本的C2.dll。大家找的时候可以使用Everything去查找相应版本的DLL,一定要相同版本。并在科锐的引导下进行了反汇编翻译,为了翻译的统一性和权威性,我们这里使用钱老师在书中附带的翻译版本。
PS:如果目标是逆向的话,C2的代码可以尝试翻译一下,可让新手获益良多,这里针对算法进行讲解。
Main函数:
钱老师使用内联汇编模拟了除法的有符号数计算,是我们上表中6、7、8、9四种情况。我们从中可以看出有符号数计算的细节:
nDivisor >= 0 和 nMagicNumber > 0 不需要增加add
nDivisor >= 0 和 nMagicNumber < 0 增加add
nDivisor < 0 和 nMagicNumber > 0 增加sub
nDivisor < 0 和 nMagicNumber < 0 不需要增加sub
然后是一个遍历进行循环测试
GetMagic函数:
首先进行函数表的匹配,如果是MagicTable中的数,之间进行使用。
如果不在MagicTable中,则从32位起进行计算。先进行预处理计算各种值,然后最关键的是do循环,不断增加nExcBase,即右移的次数。然后达到右移次数的约束条件,约束条件的证明在《C++反汇编与逆向分析技术揭秘》中有具体的证明。但是这里的循环条件是深度优化的,我看了很久,等价替换证明了很久,也不得要领。如果后面有更深的理解再行补上。
while ( q1 < nAbsDivC - r2 || q1 == nAbsDivC - r2 && !r1 );
在网上查询资料的过程中,发现了唯一一篇和MagicNumber相关的博客,该博客从正向实现了除数为无符号数的除法。我看了一下参考文献,未在其中发现vc6.0的约束条件,而是使用了更加宽泛的约束条件。在科锐学习的时间是如此的紧张,借用新年假期记录详细已然奢侈,便不在深入研究下去。
https://zhuanlan.zhihu.com/p/151038723
两篇相关论文供参考:
Division by Invariant Integers using Multiplication
Integer Division by Constants Optimal Bounds
上述内容的参考文献和代码都在附录里面提供了,感兴趣的同学可以研究一下。
/
/
加法
/
/
变量加常量
printf(
"n1 = %d\n"
, n1
+
1
);
/
/
常量加常量
printf(
"n1 = %d\n"
,
1
+
2
);
/
/
变量加变量
printf(
"n1 = %d\n"
, n1
+
n2);
/
/
加法
/
/
变量加常量
printf(
"n1 = %d\n"
, n1
+
1
);
/
/
常量加常量
printf(
"n1 = %d\n"
,
1
+
2
);
/
/
变量加变量
printf(
"n1 = %d\n"
, n1
+
n2);
VS2022_release_x86:
/
/
变量加常量
printf(
"n1 = %d\n"
, n1
+
1
);
00DC10E5
mov eax,dword ptr [esp
+
44h
]
00DC10E9
inc eax
00DC10EA
push eax
00DC10EB
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC10F0
call printf (
0DC1020h
)
/
/
常量加常量
printf(
"n1 = %d\n"
,
1
+
2
);
00DC10F5
push
3
00DC10F7
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC10FC
call printf (
0DC1020h
)
/
/
变量加变量
printf(
"n1 = %d\n"
, n1
+
n2);
00DC1101
mov eax,dword ptr [esp
+
58h
]
00DC1105
add eax,dword ptr [esp
+
54h
]
00DC1109
push eax
00DC110A
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC110F
call printf (
0DC1020h
)
VS2022_release_x86:
/
/
变量加常量
printf(
"n1 = %d\n"
, n1
+
1
);
00DC10E5
mov eax,dword ptr [esp
+
44h
]
00DC10E9
inc eax
00DC10EA
push eax
00DC10EB
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC10F0
call printf (
0DC1020h
)
/
/
常量加常量
printf(
"n1 = %d\n"
,
1
+
2
);
00DC10F5
push
3
00DC10F7
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC10FC
call printf (
0DC1020h
)
/
/
变量加变量
printf(
"n1 = %d\n"
, n1
+
n2);
00DC1101
mov eax,dword ptr [esp
+
58h
]
00DC1105
add eax,dword ptr [esp
+
54h
]
00DC1109
push eax
00DC110A
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC110F
call printf (
0DC1020h
)
/
/
减法
/
/
变量减常量
printf(
"n1 = %d\n"
, n1
-
1
);
/
/
常量减常量
printf(
"n1 = %d\n"
,
1
-
2
);
/
/
变量减变量
printf(
"n1 = %d \r\n"
, n1
-
n2);
/
/
减法
/
/
变量减常量
printf(
"n1 = %d\n"
, n1
-
1
);
/
/
常量减常量
printf(
"n1 = %d\n"
,
1
-
2
);
/
/
变量减变量
printf(
"n1 = %d \r\n"
, n1
-
n2);
VS2022_release_x86:
/
/
变量减常量
printf(
"n1 = %d\n"
, n1
-
1
);
00DC1114
mov eax,dword ptr [esp
+
5Ch
]
00DC1118
dec eax
00DC1119
push eax
00DC111A
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC111F
call printf (
0DC1020h
)
/
/
常量减常量
printf(
"n1 = %d\n"
,
1
-
2
);
00DC1124
push
0FFFFFFFFh
00DC1126
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC112B
call printf (
0DC1020h
)
/
/
变量减变量
printf(
"n1 = %d \r\n"
, n1
-
n2);
00DC1130
mov eax,dword ptr [esp
+
6Ch
]
00DC1134
sub eax,dword ptr [esp
+
70h
]
00DC1138
push eax
00DC1139
push offset string
"n1 = %d \r\n"
(
0DC3118h
)
00DC113E
call printf (
0DC1020h
)
VS2022_release_x86:
/
/
变量减常量
printf(
"n1 = %d\n"
, n1
-
1
);
00DC1114
mov eax,dword ptr [esp
+
5Ch
]
00DC1118
dec eax
00DC1119
push eax
00DC111A
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC111F
call printf (
0DC1020h
)
/
/
常量减常量
printf(
"n1 = %d\n"
,
1
-
2
);
00DC1124
push
0FFFFFFFFh
00DC1126
push offset string
"n1 = %d\n"
(
0DC310Ch
)
00DC112B
call printf (
0DC1020h
)
/
/
变量减变量
printf(
"n1 = %d \r\n"
, n1
-
n2);
00DC1130
mov eax,dword ptr [esp
+
6Ch
]
00DC1134
sub eax,dword ptr [esp
+
70h
]
00DC1138
push eax
00DC1139
push offset string
"n1 = %d \r\n"
(
0DC3118h
)
00DC113E
call printf (
0DC1020h
)
/
/
乘法
/
/
变量乘常量(常量值为非
2
的幂)
printf(
"n1 * 7 = %d\n"
, n1
*
7
);
/
/
变量乘常量(常量值为
2
的幂)
printf(
"n1 * 8 = %d\n"
, n1
*
8
);
/
/
两常量相乘
printf(
"3 * 3 = %d\n"
,
3
*
3
);
/
/
混合运算
printf(
"n1 * 6 + 5 = %d\n"
, n1
*
6
+
5
);
/
/
两变量相乘
printf(
"n1 * n2 = %d\n"
, n1
*
n2);
/
/
乘法
/
/
变量乘常量(常量值为非
2
的幂)
printf(
"n1 * 7 = %d\n"
, n1
*
7
);
/
/
变量乘常量(常量值为
2
的幂)
printf(
"n1 * 8 = %d\n"
, n1
*
8
);
/
/
两常量相乘
printf(
"3 * 3 = %d\n"
,
3
*
3
);
/
/
混合运算
printf(
"n1 * 6 + 5 = %d\n"
, n1
*
6
+
5
);
/
/
两变量相乘
printf(
"n1 * n2 = %d\n"
, n1
*
n2);
/
/
乘法
/
/
变量乘常量(常量值为非
2
的幂)
printf(
"n1 * 7 = %d\n"
, n1
*
7
);
00451143
mov eax,dword ptr [esp
+
74h
]
00451147
add esp,
40h
0045114A
lea ecx,[eax
*
8
]
00451151
sub ecx,eax
00451153
push ecx
00451154
push offset string
"n1 * 7 = %d\n"
(
0453124h
)
00451159
call printf (
0451020h
)
/
/
变量乘常量(常量值为
2
的幂)
printf(
"n1 * 8 = %d\n"
, n1
*
8
);
0045115E
mov eax,dword ptr [esp
+
3Ch
]
00451162
shl eax,
3
00451165
push eax
00451166
push offset string
"n1 * 8 = %d\n"
(
0453134h
)
0045116B
call printf (
0451020h
)
/
/
两常量相乘
printf(
"3 * 3 = %d\n"
,
3
*
3
);
00451170
push
9
00451172
push offset string
"3 * 3 = %d\n"
(
0453144h
)
00451177
call printf (
0451020h
)
/
/
混合运算
printf(
"n1 * 6 + 5 = %d\n"
, n1
*
6
+
5
);
0045117C
mov eax,dword ptr [esp
+
4Ch
]
00451180
lea eax,[eax
+
eax
*
2
]
00451183
lea eax,[eax
*
2
+
5
]
0045118A
push eax
0045118B
push offset string
"n1 * 6 + 5 = %d\n"
(
0453150h
)
00451190
call printf (
0451020h
)
/
/
两变量相乘
printf(
"n1 * n2 = %d\n"
, n1
*
n2);
00451195
mov eax,dword ptr [esp
+
58h
]
00451199
imul eax,dword ptr [esp
+
54h
]
0045119E
push eax
0045119F
push offset string
"n1 * n2 = %d\n"
(
0453164h
)
004511A4
call printf (
0451020h
)
/
/
乘法
/
/
变量乘常量(常量值为非
2
的幂)
printf(
"n1 * 7 = %d\n"
, n1
*
7
);
00451143
mov eax,dword ptr [esp
+
74h
]
00451147
add esp,
40h
0045114A
lea ecx,[eax
*
8
]
00451151
sub ecx,eax
00451153
push ecx
00451154
push offset string
"n1 * 7 = %d\n"
(
0453124h
)
00451159
call printf (
0451020h
)
/
/
变量乘常量(常量值为
2
的幂)
printf(
"n1 * 8 = %d\n"
, n1
*
8
);
0045115E
mov eax,dword ptr [esp
+
3Ch
]
00451162
shl eax,
3
00451165
push eax
00451166
push offset string
"n1 * 8 = %d\n"
(
0453134h
)
0045116B
call printf (
0451020h
)
/
/
两常量相乘
printf(
"3 * 3 = %d\n"
,
3
*
3
);
00451170
push
9
00451172
push offset string
"3 * 3 = %d\n"
(
0453144h
)
00451177
call printf (
0451020h
)
/
/
混合运算
printf(
"n1 * 6 + 5 = %d\n"
, n1
*
6
+
5
);
0045117C
mov eax,dword ptr [esp
+
4Ch
]
00451180
lea eax,[eax
+
eax
*
2
]
00451183
lea eax,[eax
*
2
+
5
]
0045118A
push eax
0045118B
push offset string
"n1 * 6 + 5 = %d\n"
(
0453150h
)
00451190
call printf (
0451020h
)
/
/
两变量相乘
printf(
"n1 * n2 = %d\n"
, n1
*
n2);
00451195
mov eax,dword ptr [esp
+
58h
]
00451199
imul eax,dword ptr [esp
+
54h
]
0045119E
push eax
0045119F
push offset string
"n1 * n2 = %d\n"
(
0453164h
)
004511A4
call printf (
0451020h
)
/
/
1.
除数为无符号
2
的幂
printf(
"argc / 16 = %u\n"
, (unsigned)argc
/
16
);
00007FF72988107D
lea rcx,[string
"argc / 16 = %u\n"
(
07FF72989E3E0h
)]
00007FF729881084
mov edx,ebx
00007FF729881086
shr edx,
4
00007FF729881089
call printf (
07FF729881010h
)
printf(
"argc / 16 = %llu\n"
, (unsigned
long
long
)argc
/
16
);
00007FF72988108E
mov rdx,rbx
00007FF729881091
lea rcx,[string
"argc / 16 = %llu\n"
(
07FF72989E3F0h
)]
00007FF729881098
shr rdx,
4
00007FF72988109C
call printf (
07FF729881010h
)
/
/
1.
除数为无符号
2
的幂
printf(
"argc / 16 = %u\n"
, (unsigned)argc
/
16
);
00007FF72988107D
lea rcx,[string
"argc / 16 = %u\n"
(
07FF72989E3E0h
)]
00007FF729881084
mov edx,ebx
00007FF729881086
shr edx,
4
00007FF729881089
call printf (
07FF729881010h
)
printf(
"argc / 16 = %llu\n"
, (unsigned
long
long
)argc
/
16
);
00007FF72988108E
mov rdx,rbx
00007FF729881091
lea rcx,[string
"argc / 16 = %llu\n"
(
07FF72989E3F0h
)]
00007FF729881098
shr rdx,
4
00007FF72988109C
call printf (
07FF729881010h
)
/
/
2.
除数为无符号非
2
的幂(上)
printf(
"argc / 9 = %d"
, (unsigned)argc
/
9
);
00007FF7298810A1
mov eax,
38E38E39h
00007FF7298810A6
lea rcx,[string
"argc / 9 = %d"
(
07FF72989E408h
)]
00007FF7298810AD
mul eax,ebx
00007FF7298810AF
shr edx,
1
00007FF7298810B1
call printf (
07FF729881010h
)
printf(
"argc / 9 = %d"
, (unsigned
long
long
)argc
/
9
);
00007FF7298810B6
mov rax,
0E38E38E38E38E38Fh
00007FF7298810C0
lea rcx,[string
"argc / 9 = %d"
(
07FF72989E408h
)]
00007FF7298810C7
mul rax,rbx
00007FF7298810CA
shr rdx,
3
00007FF7298810CE
call printf (
07FF729881010h
)
/
/
2.
除数为无符号非
2
的幂(上)
printf(
"argc / 9 = %d"
, (unsigned)argc
/
9
);
00007FF7298810A1
mov eax,
38E38E39h
00007FF7298810A6
lea rcx,[string
"argc / 9 = %d"
(
07FF72989E408h
)]
00007FF7298810AD
mul eax,ebx
00007FF7298810AF
shr edx,
1
00007FF7298810B1
call printf (
07FF729881010h
)
printf(
"argc / 9 = %d"
, (unsigned
long
long
)argc
/
9
);
00007FF7298810B6
mov rax,
0E38E38E38E38E38Fh
00007FF7298810C0
lea rcx,[string
"argc / 9 = %d"
(
07FF72989E408h
)]
00007FF7298810C7
mul rax,rbx
00007FF7298810CA
shr rdx,
3
00007FF7298810CE
call printf (
07FF729881010h
)
公式:C
=
2
^n
/
M
>>>
pow
(
2
,
33
)
/
0x38E38E39
8.999999998952262
>>>
pow
(
2
,
67
)
/
0x0E38E38E38E38E38F
9.0
公式:C
=
2
^n
/
M
>>>
pow
(
2
,
33
)
/
0x38E38E39
8.999999998952262
>>>
pow
(
2
,
67
)
/
0x0E38E38E38E38E38F
9.0
/
/
3.
除数为无符号非
2
的幂(下)
printf(
"argc / 7 = %d"
, (unsigned)argc
/
7
);
00007FF7298810D3
mov eax,
24924925h
00007FF7298810D8
lea rcx,[string
"argc / 7 = %d"
(
07FF72989E418h
)]
00007FF7298810DF
mul eax,ebx
00007FF7298810E1
mov eax,ebx
00007FF7298810E3
sub eax,edx
00007FF7298810E5
shr eax,
1
00007FF7298810E7
add edx,eax
00007FF7298810E9
shr edx,
2
00007FF7298810EC
call printf (
07FF729881010h
)
printf(
"argc / 7 = %d"
, (unsigned
long
long
)argc
/
7
);
00007FF7298810F1
mov rax,
2492492492492493h
00007FF7298810FB
lea rcx,[string
"argc / 7 = %d"
(
07FF72989E418h
)]
00007FF729881102
mul rax,rbx
00007FF729881105
mov rax,rbx
00007FF729881108
sub rax,rdx
00007FF72988110B
shr rax,
1
00007FF72988110E
add rdx,rax
00007FF729881111
shr rdx,
2
00007FF729881115
call printf (
07FF729881010h
)
/
/
3.
除数为无符号非
2
的幂(下)
printf(
"argc / 7 = %d"
, (unsigned)argc
/
7
);
00007FF7298810D3
mov eax,
24924925h
00007FF7298810D8
lea rcx,[string
"argc / 7 = %d"
(
07FF72989E418h
)]
00007FF7298810DF
mul eax,ebx
00007FF7298810E1
mov eax,ebx
00007FF7298810E3
sub eax,edx
00007FF7298810E5
shr eax,
1
00007FF7298810E7
add edx,eax
00007FF7298810E9
shr edx,
2
00007FF7298810EC
call printf (
07FF729881010h
)
printf(
"argc / 7 = %d"
, (unsigned
long
long
)argc
/
7
);
00007FF7298810F1
mov rax,
2492492492492493h
00007FF7298810FB
lea rcx,[string
"argc / 7 = %d"
(
07FF72989E418h
)]
00007FF729881102
mul rax,rbx
00007FF729881105
mov rax,rbx
00007FF729881108
sub rax,rdx
00007FF72988110B
shr rax,
1
00007FF72988110E
add rdx,rax
00007FF729881111
shr rdx,
2
00007FF729881115
call printf (
07FF729881010h
)
公式 C
=
2
^n
/
(
2
^
32
+
M)
=
2
^n
/
(
2
^
64
+
M)
>>>
pow
(
2
,
35
)
/
(
pow
(
2
,
32
)
+
0x24924925
)
6.99999999938882
>>>
pow
(
2
,
67
)
/
(
pow
(
2
,
64
)
+
0x2492492492492493
)
7.0
公式 C
=
2
^n
/
(
2
^
32
+
M)
=
2
^n
/
(
2
^
64
+
M)
>>>
pow
(
2
,
35
)
/
(
pow
(
2
,
32
)
+
0x24924925
)
6.99999999938882
>>>
pow
(
2
,
67
)
/
(
pow
(
2
,
64
)
+
0x2492492492492493
)
7.0
/
/
4.
除数为有符号
2
的幂
printf(
"argc / -4 = %d"
, argc
/
8192
);
00007FF72988111A
mov eax,ebx
00007FF72988111C
lea rcx,[string
"argc / -4 = %d"
(
07FF72989E428h
)]
00007FF729881123
cdq
00007FF729881124
and
edx,
1FFFh
00007FF72988112A
add edx,eax
00007FF72988112C
sar edx,
0Dh
00007FF72988112F
call printf (
07FF729881010h
)
printf(
"argc / -4 = %d"
, (
long
long
)argc
/
8192
);
00007FF729881134
mov rax,rbx
00007FF729881137
lea rcx,[string
"argc / -4 = %d"
(
07FF72989E428h
)]
00007FF72988113E
cqo
00007FF729881140
and
edx,
1FFFh
00007FF729881146
add rdx,rax
00007FF729881149
sar rdx,
0Dh
00007FF72988114D
call printf (
07FF729881010h
)
/
/
4.
除数为有符号
2
的幂
printf(
"argc / -4 = %d"
, argc
/
8192
);
00007FF72988111A
mov eax,ebx
00007FF72988111C
lea rcx,[string
"argc / -4 = %d"
(
07FF72989E428h
)]
00007FF729881123
cdq
00007FF729881124
and
edx,
1FFFh
00007FF72988112A
add edx,eax
00007FF72988112C
sar edx,
0Dh
00007FF72988112F
call printf (
07FF729881010h
)
printf(
"argc / -4 = %d"
, (
long
long
)argc
/
8192
);
00007FF729881134
mov rax,rbx
00007FF729881137
lea rcx,[string
"argc / -4 = %d"
(
07FF72989E428h
)]
00007FF72988113E
cqo
00007FF729881140
and
edx,
1FFFh
00007FF729881146
add rdx,rax
00007FF729881149
sar rdx,
0Dh
00007FF72988114D
call printf (
07FF729881010h
)
公式 C
=
pow
(
2
,n)
>>>
pow
(
2
,
13
)
8192
>>>
pow
(
2
,
13
)
8192
公式 C
=
pow
(
2
,n)
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2022-1-29 00:21
被瑞皇编辑
,原因: