Assume EDX:EAX and EBX:ECX pairs hold two 64 bit values that are to be added together.
add eax, ecx
adc edx, ebx
mov dword [ebp+Some64BitValue], eax
mov dword [ebp+Some64BitValue+4], edx
我无法理解的含义是当ADC连续使用像这样的变量/寄存器:
add eax, dword [esi]
adc eax, dword [esi+0x4]
adc eax, dword [esi+0x8]
adc eax, dword [esi+0x10]
...
adc eax, 0
一般来说,这样做的目的是什么?什么是EAX?
* update:
请参阅下面的答案
#1 楼
我找到了问题的答案。EAX是任意的,[ESI]中添加的值也是任意的。
我要反转的函数是一个计算将数据按上述方式累加在一起后,再将16位校验和,然后将EAX中的结果折叠到AX中。我正在查看的是类似于此处描述的Internet校验和。
在这种情况下,连续ADC指令的目的看起来像是仅在汇编级别可用的优化。校验和执行多次称赞加法。仅使用ADD才能执行相同操作的另一种方法是让进位位在寄存器的上半部分累加,然后在末尾将它们加回到下半部分。
#2 楼
编辑2无需求助于内联汇编/单独的汇编模块,我能够使用固有的_addcarry_uxx(16,32,64)生成连续的adc指令(在msvc cl中对/ O1开关进行了全面优化。 exe)
相关代码及其下面的反汇编
#include <stdio.h>
#include <intrin.h>
#define BUSIZ 16
#define UNROLL 8
unsigned int dat[BUSIZ] =
{
0x10001337, 0xffffffff, 0x10001337 , 0xffffffff,
0x00001337, 0xdeadbeef, 0xbeadbed5 , 0xdad15dad,
0xba5eba11, 0xf001b055, 0xc001b055 , 0x501eb055,
0xba11ba75, 0xbadba115, 0xbed15bad , 0xdaff0d11
};
int main (void)
{
unsigned int chksum = 0;
unsigned char carry = 0;
for(int i=0; i< BUSIZ; i += UNROLL )
{
carry = _addcarry_u32(carry,chksum,dat[i+0],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+1],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+2],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+3],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+4],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+5],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+6],&chksum);
carry = _addcarry_u32(carry,chksum,dat[i+7],&chksum);
}
printf("FINAL CHECKSUM = %8x\n" , chksum + carry );
return 0;
}
执行后将打印出
:\>addcarry.exe
FINAL CHECKSUM = 616ba476
通过python脚本检查结果的准确性
:\>cat chksum.py
dat = [
0x10001337, 0xffffffff, 0x10001337 , 0xffffffff,
0x00001337, 0xdeadbeef, 0xbeadbed5 , 0xdad15dad,
0xba5eba11, 0xf001b055, 0xc001b055 , 0x501eb055,
0xba11ba75, 0xbadba115, 0xbed15bad , 0xdaff0d11
]
chksum33bit = 0
for i in range (0,16,1):
chksum33bit = chksum33bit + dat[i]
chklow = chksum33bit & 0xffffffff
chkhig = chksum33bit >> 32
chkfin = chklow+chkhig
print (hex(chkfin))
:\>python chksum.py
0x616ba476L
反汇编我们看到编译器生成了连续的adc指令
:\>cdb -c "uf addcarry!main;q" addcarry.exe | grep -B 31 quit
0:000> cdb: Reading initial command 'uf addcarry!main;q'
addcarry!main:
01151029 33c9 xor ecx,ecx
0115102b b804901901 mov eax,offset addcarry!dat+0x4 (01199004)
01151030 8ad1 mov dl,cl
addcarry!main+0x9:
01151032 80c2ff add dl,0FFh
01151035 1348fc adc ecx,dword ptr [eax-4]
01151038 1308 adc ecx,dword ptr [eax]
0115103a 134804 adc ecx,dword ptr [eax+4]
0115103d 134808 adc ecx,dword ptr [eax+8]
01151040 13480c adc ecx,dword ptr [eax+0Ch]
01151043 134810 adc ecx,dword ptr [eax+10h]
01151046 134814 adc ecx,dword ptr [eax+14h]
01151049 134818 adc ecx,dword ptr [eax+18h]
0115104c 0f92c2 setb dl
0115104f 83c020 add eax,20h
01151052 3d44901901 cmp eax,offset addcarry!__scrt_default_matherr (01199044)
01151057 7cd9 jl addcarry!main+0x9 (01151032)
addcarry!main+0x30:
01151059 0fb6c2 movzx eax,dl
0115105c 03c1 add eax,ecx
0115105e 50 push eax
0115105f 6890011901 push offset addcarry!`string' (01190190)
01151064 e805000000 call addcarry!printf (0115106e)
01151069 59 pop ecx
0115106a 59 pop ecx
0115106b 33c0 xor eax,eax
0115106d c3 ret
quit:
编辑结束2
编辑1:
即使我可以生成多个ADC,但我无法成功生成
连续的ADC使用c编译器
,所以我环顾了Windows \ system32目录,如果任何二进制文件具有连续的adc,而
位于imagehlp.dll中
,并且在进行谷歌搜索之后,它似乎是RFC1071 IP标头校验和br />大概是用手写汇编编写的(找到了一些汇编代码s代表Motorola,cray等,这也是一个Google小组链接,讨论了ChkSum的实现,还有一个旧的Dave Cutler从NT图像帮助工具包sdk编写的ChkSum(),该工具包由ms于1993年左右发布) >
下面是win7 sp1 32位imagehlp.dll ADC序列
grep -obUaPs "\x13\x46\x04\x13\x46\x08" --include=*.dll *
imagehlp.dll:17883:‼F♦‼F
imagehlp.dll:17917:‼F♦‼F
imagehlp.dll:17963:‼F♦‼F
imagehlp.dll:18021:‼F♦‼F
xxd -c 12 -g 3 -s 18021 -l 99 imagehlp.dll
0004665: 134604 134608 13460c 134610 .F..F..F..F.
0004671: 134614 134618 13461c 134620 .F..F..F..F
000467d: 134624 134628 13462c 134630 .F$.F(.F,.F0
0004689: 134634 134638 13463c 134640 .F4.F8.F<.F@
0004695: 134644 134648 13464c 134650 .FD.FH.FL.FP
00046a1: 134654 134658 13465c 134660 .FT.FX.F\.F`
00046ad: 134664 134668 13466c 134670 .Fd.Fh.Fl.Fp
00046b9: 134674 134678 13467c 83d000 .Ft.Fx.F|...
00046c5: 81c680 ...
dumpbin /headers imagehlp.dll | grep -i "section header #1" -A 5
SECTION HEADER #1
.text name
23249 virtual size
1000 virtual address (41871000 to 41894248)
23400 size of raw data
600 file pointer to raw data (00000600 to 000239FF)
cdb -c "ln (imagehlp + 1000 + (0n18021-0x600));q" -z imagehlp.dll | grep -i -A 1 reading
0:000> cdb: Reading initial command 'ln (imagehlp + 1000 + (0n18021-0x600));q'
(41874f7b) imagehlp!ChkSum+0xea | (41875105) imagehlp!_SEH_prolog4_GS
编辑结束1
可能有多个ADC因为未对编译进行优化是
的原因之一,假设您有这样的代码
#include <stdio.h>
#include <windows.h>
int main (void) {
DWORD64 a = 0x100002000;
DWORD64 b = 0x00000000ffffffff;
DWORD64 c = a + b;
printf("%I64x\n" , a);
printf("%I64x\n" , b);
printf("%I64x\n" , c);
c = c + a;
printf("%I64x\n" , c);
c = c + b;
printf("%I64x\n" , c);
c = c + c;
printf("%I64x\n" , c);
return 0;
}
如果不进行优化就进行编译
反汇编函数主函数并查找adc指令
您将看到几条adc指令,包括一些使用同一寄存器的
cl /Zi /EHsc /W4 /Od /nologo /analyze adc.cpp /link /release /nologo adc.cpp
cdb -c "g adc!main;uf .;q" adc.exe | grep -i "adc "
000a102b 134dec adc ecx,dword ptr [ebp-14h]
000a107c 1345f4 adc eax,dword ptr [ebp-0Ch]
000a10a3 134dec adc ecx,dword ptr [ebp-14h]
000a10ca 1355fc adc edx,dword ptr [ebp-4]
,但是如果您进行了优化编译器足够聪明,可以删除所有Adc指令
cl /Zi /EHsc /W4 /Ox /nologo /analyze adc.cpp /link /release /nologo adc.cpp
cdb -c "g adc!main;uf .;q" adc.exe | grep -i "adc "
adc.exe
100002000
ffffffff
200001fff
300003fff
400003ffe
800007ffc
您有问题的代码可能是执行纯加法并返回结果的子例程的结果,如下所示
#include <stdio.h>
#include <windows.h>
#pragma optimize ( "t" , off)
DWORD64 madd (DWORD64 a, DWORD64 b)
{
DWORD64 c = 0;
c = a + b;
c = c + a;
c = c + b;
c = c + c;
return c;
}
#pragma optimize ( "t" , on)
int main (void) {
DWORD64 a = 0x100002000;
DWORD64 b = 0x00000000ffffffff;
printf("%I64x\n" , madd(a,b));
return 0;
}
这里是反汇编添加了multi64位的函数的结果值并返回结果
反汇编函数madd
0:000> uf adc!madd
adc!madd [adc.cpp @ 6]:
6 00291000 55 push ebp
6 00291001 8bec mov ebp,esp
6 00291003 51 push ecx
6 00291004 51 push ecx
7 00291005 0f57c0 xorps xmm0,xmm0
7 00291008 660f1345f8 movlpd qword ptr [ebp-8],xmm0
8 0029100d 8b4508 mov eax,dword ptr [ebp+8]
8 00291010 034510 add eax,dword ptr [ebp+10h]
8 00291013 8b4d0c mov ecx,dword ptr [ebp+0Ch]
8 00291016 134d14 adc ecx,dword ptr [ebp+14h]
8 00291019 8945f8 mov dword ptr [ebp-8],eax
8 0029101c 894dfc mov dword ptr [ebp-4],ecx
9 0029101f 8b45f8 mov eax,dword ptr [ebp-8]
9 00291022 034508 add eax,dword ptr [ebp+8]
9 00291025 8b4dfc mov ecx,dword ptr [ebp-4]
9 00291028 134d0c adc ecx,dword ptr [ebp+0Ch]
9 0029102b 8945f8 mov dword ptr [ebp-8],eax
9 0029102e 894dfc mov dword ptr [ebp-4],ecx
10 00291031 8b45f8 mov eax,dword ptr [ebp-8]
10 00291034 034510 add eax,dword ptr [ebp+10h]
10 00291037 8b4dfc mov ecx,dword ptr [ebp-4]
10 0029103a 134d14 adc ecx,dword ptr [ebp+14h]
10 0029103d 8945f8 mov dword ptr [ebp-8],eax
10 00291040 894dfc mov dword ptr [ebp-4],ecx
11 00291043 8b45f8 mov eax,dword ptr [ebp-8]
11 00291046 0345f8 add eax,dword ptr [ebp-8]
11 00291049 8b4dfc mov ecx,dword ptr [ebp-4]
11 0029104c 134dfc adc ecx,dword ptr [ebp-4]
11 0029104f 8945f8 mov dword ptr [ebp-8],eax
11 00291052 894dfc mov dword ptr [ebp-4],ecx
12 00291055 8b45f8 mov eax,dword ptr [ebp-8]
12 00291058 8b55fc mov edx,dword ptr [ebp-4]
14 0029105b c9 leave
14 0029105c c3 ret
函数使用相同的寄存器ecx来添加多个结转
0:000> # adc*, adc!madd l 60
adc!madd+0x16 [adc.cpp @ 8]:
00291016 134d14 adc ecx,dword ptr [ebp+14h]
adc!madd+0x28 [adc.cpp @ 9]:
00291028 134d0c adc ecx,dword ptr [ebp+0Ch]
adc!madd+0x3a [adc.cpp @ 10]:
0029103a 134d14 adc ecx,dword ptr [ebp+14h]
adc!madd+0x4c [adc.cpp @ 11]:
0029104c 134dfc adc ecx,dword ptr [ebp-4]
0:000>
评论
您可以发布更大的代码段吗?例如eax如何初始化?