能力值:
( LV5,RANK:60 )
2 楼
and esp, 0FFFFFFF8h应该是取栈框架的顶指针,低3位清0而已
能力值:
( LV10,RANK:170 )
3 楼
应该是拿起来用着局部变量的,不过很少看到有编译器会如此的!
能力值:
( LV13,RANK:530 )
4 楼
编译器优化存放局部变量而已。VC在可以省略的地方都会尽量省略 但是如果开了省略框架指针则省略更多而已
能力值:
( LV8,RANK:130 )
5 楼
add ? and?
能力值:
( LV3,RANK:20 )
6 楼
AND
如果是add的话,就不用问了,呵呵
能力值:
( LV3,RANK:20 )
7 楼
我还是不明白是怎么优化的,前面已经有 push ebp mov ebp,esp 这两条了,下来根据ebp来对局部变量寻址已经很直接了,干吗还要 AND 一下?
能力值:
(RANK:1060 )
8 楼
align 4
不会是某些手工“免杀”的结果把。。。
能力值:
( LV2,RANK:10 )
9 楼
对齐作用。。。。。。 比如想 某个内存都是 X的N倍。。。。
能力值:
( LV13,RANK:530 )
10 楼
看错 以为是 and [esp],XX
这句话还是看上下文吧。一般编译器貌似不会直接生成。esp要最为堆叠指针的。不能够这样用。
除非在壳中。
能力值:
( LV13,RANK:530 )
11 楼
每个编译器使实现不一样。。你说的这个市intel C++ 的实现方法。
int _tmain(int argc, _TCHAR* argv[])
{
0040105C push ebp
0040105D mov ebp,esp
0040105F sub esp,3
00401062 and esp,0FFFFFFF8h
00401065 add esp,4
00401068 sub esp,38h
0040106B mov eax,dword ptr [___security_cookie (403000h)]
00401070 mov dword ptr [ebp-4],eax
wchar_t buf[16];
这是在Intel C++ 10的优化下 and esp,FFFFFFF0 可见这句。
可以推测是结构堆对齐
00401000 T>/$ 55 push ebp
00401001 |. 8BEC mov ebp,esp
00401003 |. 83E4 F0 and esp,FFFFFFF0
00401006 |. 83EC 20 sub esp,20
00401009 |. 6A 03 push 3
0040100B |. E8 D4000000 call TEST_2.004010E4
00401010 |. 8D4424 04 lea eax,dword ptr ss:[esp+4]
00401014 |. 68 2E104000 push TEST_2.0040102E ; /<%d> = 40102E (4198446.)
00401019 |. 68 3C204000 push TEST_2.0040203C ; |Format = "%d"
0040101E |. 50 push eax ; |s
0040101F |. FF15 08204000 call dword ptr ds:[<&USER32.wsprintfW>] ; \wsprintfW
00401025 |. 83C4 10 add esp,10
00401028 |. 33C0 xor eax,eax
0040102A |. 8BE5 mov esp,ebp
0040102C |. 5D pop ebp
0040102D \. C3 retn
关闭优化下
0040105C T>/$ 55 push ebp
0040105D |. 8BEC mov ebp,esp
0040105F |. 83EC 03 sub esp,3
00401062 |. 83E4 F8 and esp,FFFFFFF8
00401065 |. 83C4 04 add esp,4
00401068 |. 83EC 2C sub esp,2C
0040106B |. A1 00204000 mov eax,dword ptr ds:[<&USER32.wsprintfW>]
00401070 |. 83C4 00 add esp,0
00401073 |. 8D55 E0 lea edx,[local.8] ; |
00401076 |. 891424 mov dword ptr ss:[esp],edx ; |
00401079 |. C74424 04 00304000 mov dword ptr ss:[esp+4],TEST_2.00403000 ; |UNICODE "%d"
00401081 |. C74424 08 00104000 mov dword ptr ss:[esp+8],TEST_2.00401000 ; |
00401089 |. FFD0 call eax ; \wsprintfW
0040108B |. 83C4 0C add esp,0C
0040108E |. 33C0 xor eax,eax
00401090 |. C9 leave
00401091 \. C3 retn
确实Intel C++的优化达到了前所未有的高度。。令人叹为观止。
能力值:
( LV3,RANK:20 )
12 楼
哈哈,结构对齐,有些明白了,我推测前面的push ebp, mov ebp,esp 应该是为了用ebp对函数的参数进行寻址,后面的 and esp,FFFFFFF8h 应该为了对栈上的临时结构变量进行8byte对齐而采取的措施,如果要16byte对齐,就会象你的第2段代码那样是 and esp,FFFFFFF0h 。也就是说如果编译器已经推测到栈上的临时变量可以进行8或16byte对齐寻址,在打开某个优化开关的情况下,应该会生产这样的代码的。
另外,我看的代码应该是VC的,可能我们还不知道VC的那个优化选项决定这个东西。
很佩服 foxabu 大侠能对不同编译器分析的这么透彻,有点象K8的那本书了,谢谢指教!
能力值:
( LV13,RANK:530 )
13 楼
‘如果要16byte对齐,就会象你的第2段代码 不是要,而是打开速度优化的前提下’
如果用第一种未优化 会花费三条指令。 而第二种显然只要一条。空间换时间。不过也谈不上 反正堆栈只要不溢出。内存也不会浪费。leave ret以后反正还要恢复原始esp的。
另外纠正一个说法。准确地说你说的VC只是代码 是C++的或者说VC++的 只有编译器,只要符合C++标准的都可以编译嘛。所以你这个代码是有可能是Intel C++ 编译器编译的。VC中基本上还看不到这种(不排除我见得太少。希望多指教),根据你说的每个函数 来推测。
能力值:
( LV3,RANK:20 )
14 楼
关于编译器的问题,我可以确定是VC编译的,因为IDA已经识别出足够多的MFC和VCrtl函数。
不过关于临时变量存取的优化的方法,由于我看的代码在sub esp,xxx以后就被VMProtect
掉了,所以也没有看出什么来。我只是猜想也许在对齐的情况下,对临时变量可能是如下访问的:
lea Exx,[esp+n*Exx]
push Exx
也许这样做比 push [ebp+xxx] 要快一些吧?
不过这都是瞎猜的,还请大家多指教。
能力值:
( LV13,RANK:530 )
15 楼
,,,,,晕.....
MFC 的是可以用Intel C++ 甚至 Borland C++ 编译的!!
你把同样的VC代码 原封不动 直接交给Intel C++编译器编译就行了。再说库是微软编写好的静态或者动态库,Runtime Package段是VC++的也非常正常。。
---------------------------------------------------------------------------
奥 建议楼主补充一些知识。MFC 就代表是VC的?难道Borland C++不可以用?。。。如有得罪之处 多多包涵。我这个人比较偏激。
能力值:
( LV3,RANK:20 )
16 楼
多谢指导,没有感觉到有偏激的问题,欢迎多对我拍砖头,呵呵
不过我觉得我们说的是一个问题的两个方向,foxabu是通过特征代码来确定编译器的,而我是通过其他的一些方法来确认编译器,然后确认这个编译器也有类似的特征代码。我明白VC的代码可以使用其他的编译器来编译,不过我之所以觉得是VC编译的,除了IDA识别到的函数以外,IDA自身也自动识别这个程序是VC编译(我看的这个EXE只用了VMProtect保护了很小一部分的关键代码,没有再加其他壳,所以应该很容易识别的),同时我看到一些SEH函数,我认为对SEH的处理应该能表明编译器的特征。我没有看过intel C++编译的代码,但我现在看到的SEH代码和以前看过的VC编译出来的是很相似的。
请多指正。
能力值:
( LV2,RANK:10 )
17 楼
以下是Hacker Disassembling Uncovered中的原文:
Alignment in the stack In some cases, elements of a structure, an array, or even particular variables must be aligned by addresses that are multiples of a specific power of 2. However, the stack-top pointer value is not defined beforehand. How can the compiler, which does not know the index value, fulfill this requirement? It simply discards the lower bits of ESP.
The lower bit of even numbers is zero. To ensure that the value of the stack-top pointer is divisible by two without a remainder, simply force its lower bit to zero. If two lower bits are set to zero, the resulting value will be a multiple of four; if three lower bits are set to zero, the resulting value will be a multiple of eight; and so on.
In most cases, bits are reset using the AND instruction. For example, AND ESP, FFFFFF0 makes ESP a multiple of 16. How do we obtain this? Let's convert 0xFFFFFFF0 to a binary form, which will give the following: 111111111 11111111 11110000. The four trailing zeroes mean that four lower bits of any number will be masked. The number will be divisible by 2 to the power of 4, which equals 16.
能力值:
( LV13,RANK:530 )
18 楼
我都说了SEH使用的库完全有可能是由VC 编译好的
绝大多数都是这种情况
一般没有人去编译MSVCRT.lib吧?很显然SEH结构化处理 包括try catch 的编译器 thunk都是VC的 这个一点也不奇怪。
另外我的判断根据是:公开的VC++编译器 至少 6 7 8 没有发现这种优化。虽然说我不一定说就是VC。但是很显然不是Borland C++ 至于是不是G++或者GCC 这个就不清楚(但是貌似无法编译MFC的程序,有些是Microsoft Special 的代码。)。反正主流编译器就这么几种。不排除作者自己写编译器。而且我给出的示例代码也证明了Intel C++ 可以生成。我只说普遍性问题 仅根据楼主的 每一个函数头前面生成。这几个字。
况且IDA什么时候可以识别Intel C++?,不能够识别,就无法推断就是VC!况且那个东西也能够使人相信。。。。。
推荐楼主自己试验,把能够编译MFC的且符合你所说的程序环境的编译器都拿来测试就知道了。