能力值:
( LV9,RANK:230 )
|
-
-
2 楼
1.ret结束程序和ExitProcess的区别
在堆栈平衡的情况下,用ret结束程序,系统自然会调用ExitThread来结束线程;另外,如果是单线程进程,系统自然还会调用ExitProcess。然而,在这里我要说尽量不要使用ret结束进程或线程,原因如下:
第一,汇编语言本身的特性使得我们,有可能因编程失误在结束程序前,堆栈并不平衡。
第二,一些壳可能不清理堆栈,或者某些对二进制代码的二次开发操作的不严谨,也会产生同样的问题。
2.masn怎么使用unicode
使用masm库ucmacros.asm,在它里面有的两个宏:WSTR和uni$。自己看一看就明白了,非常容易理解。
3.第四种工作模式
Pentium及其后继处理器在“实模式、保护模式、虚拟86模式”基础上,又增加了一个“系统管理模式”,目的是实现对系统供电和系统功能进行管理。
4.以编程的角度用汇编实现C语言中的switch
搞逆向的同志对这个问题再熟悉不过了,当然以编程的角度会略有不同。
[1]分支数较少的实现——多个if
一般来说如果分支数少于4个或者分支条件不连续分布,那么我们直接用多个.if来实现就可以,如下:
.code
Start:
mov eax, xxxx
cmp eax,0
je BRA0
cmp eax,1
je BRA1
cmp eax,2
je BRA2
cmp eax,3
je BRA3
BRA0:
.....
BRA1:
.....
BRA2:
.....
BRA3:
.....
End Start
[2]分支数较多的实现——跳转表法
采用.if条件二叉分支的方法,虽然简单,但随着分支数的增加,进入最后分支的等待平均时间越来越长,这极大的削弱了汇编语言的优势,为此提出了跳转表法。
具体做法:在内存中开辟一块连续的存储单元作为跳转表,表中按顺序存放各分支的跳转地址,进入分支处理程序前,通过查询跳转表来确定跳转地址。如下:
.Data
BASET dw BAR0,BAR1,BAR2,BAR3,…
.code
mov eax, xxxx
add eax,offset BASET
jmp dword ptr [eax]
BAR0:
.....
BAR1:
.....
BAR2:
.....
BAR3:
.....
5.用汇编实现函数递归调用
其实这个很简单了,看下面的代码就可以了
fun proc
pushaf
.....
cmp xxx,xxx ;判断是否达到递归终值
jz Last
..... ;在这里进行某些递归过程内运算
call fun;递归调用
jmp Fun_End
Last:
.....
mov xxx,xxx;给递归条件赋予递归终值
Fun_End:
popaf
ret
fun endp
|
能力值:
( LV9,RANK:170 )
|
-
-
3 楼
为什么不能用 [esp+esp] 这种寻址模式?
为什么会有 pusha/popa, pushw/popw, pushad/popad 这些形式?
--------------------------------------------------
如果不解释原因,使人更加迷糊
|
能力值:
( LV9,RANK:230 )
|
-
-
4 楼
[QUOTE=mik;927446]为什么不能用 [esp+esp] 这种寻址模式?
为什么会有 pusha/popa, pushw/popw, pushad/popad 这些形式?
--------------------------------------------------
如果不解释原因,使人更加迷糊[/QUOTE]
第一问题不太好回答,简单讲是因为机器指令格式的sid字段,表示[esp+esp]的对应值被[esp]占用,原来位于r/m字段表示[esp]的值表示了其他意义。具体要明白这个问题得有比较深入的32位机器指令格式的基础。
push/pop有那么多形式估计是兼容以前16位指令的原因。
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
虽然我的汇编基本上一窍不通,不过看了楼主的教学,还是有点收获的,谢谢了啊
|
能力值:
( LV6,RANK:80 )
|
-
-
6 楼
[QUOTE=yangbostar;927449]第一问题不太好回答,简单讲是因为机器指令格式的sid字段,表示[esp+esp]的对应值被[esp]占用,原来位于r/m字段表示[esp]的值表示了其他意义。具体要明白这个问题得有比较深入的32位机器指令格式的基础。
push/pop有那么多形式估计是兼容以前16位指令的原因。[/QUOTE]
你这样说不对,[esp+esp]确实存在而非不存在 你不能在一般的汇编器里过去那是汇编器的事情。事实上这个问题是sib的index如果为esp的话,就自动解释成index项无效。这样说比较抽象,举个例子来看。
mov eax,[esp+esp]
如果你在通常汇编器里面写是写不出来的 因为sib.index为esp(=100)会被认为index错误
但是这指令是存在编码的 32位下 一般为
8b 04 24
为了说清楚这个事情 我们把后面的24给拆成二进制
00 10 0 100
红字的1 0 0就是esp作为sib.index的编码 在我的VC6下面要想看出效果 需要使用这样的
嵌入汇编
__asm
{
//mov eax,[esp+esp]
_emit 0x8b
_emit 0x04
_emit 0x24
}
你可以调试时候看看vc的反汇编代码 这句话 反汇编成了mov eax,[esp] 也就是说 同样作为index的esp被忽略了 index*scale这一项没有了。
|
能力值:
( LV9,RANK:230 )
|
-
-
7 楼
[QUOTE=爱鸟;928871]你这样说不对,[esp+esp]确实存在而非不存在 你不能在一般的汇编器里过去那是汇编器的事情。事实上这个问题是sib的index如果为esp的话,就自动解释成index项无效。这样说比较抽象,举个例子来看。
mov eax,[esp+esp]
如果你在通常汇编器里面写是写不出来的 因为sib....[/QUOTE]
我不同意你的说法,我们来编译这一句mov eax,[esp],编译的结果也是8b 04 24,sib=24,我们可以看出事实上,是[esp]把[esp+esp]占用了,而不是存在所谓的[esp+esp]。
为什么[esp]要占用[esp+esp]呢?
原因是这样,原本[esp]只要在Mod R/M字节中的r/m域里表示为100就可以,但是Mod R/M承担了一个责任,就是提示在指令里是否存在SIB字节,然而Mod R/M为没有专门的域,来表示这个提示,所以只好占用Mod r/m中R/m域表示[esp]的100,而把[esp]挪到SIB字节里表示,而[esp]选择的方法是占用sib里表示[esp+esp]的值,因此不存在所谓[esp+esp]。
|
能力值:
( LV6,RANK:80 )
|
-
-
8 楼
[QUOTE=yangbostar;929035]我不同意你的说法,我们来编译这一句mov eax,[esp],编译的结果也是8b 04 24,sib=24,我们可以看出事实上,是[esp]把[esp+esp]占用了,而不是存在所谓的[esp+esp]。
为什么[esp]要占用[esp+esp]呢?
原因是这样,原本[esp]只要在Mod ...[/QUOTE]
这个解释大有可说。我们从头开始看。
modrm提供reg [reg] [reg+disp]三种寻址
sib本是可选字段 由modrm的rm字段=100[esp]来引导出来 这样用[esp]方式的寻址 就必须用sib 然后用sib.base的为esp来实现
sib能够寻址的是[base+index*scale+dispXX]
难就难在这个scale scale只有两位 对应是四种编码 1 2 4 8 而没有对应0的编码 这样
[esp]=[esp+0*index]就没法表示
走到这里我们发现sib没法表示[esp]寻址模式了 于是intel只能作出一个艰难的决定 当esp作为sib基址寄存器时候 通过某种方式直接把scale视为0 也就是说 如果sib.base=100时候 如果index是=100 则视为scale=0 实现了[esp]的寻址
这样回头看 我们来看看esp为什么不能做index 事实上 就算不是esp作为基址 当index=100 时候 scale同样也是视为0的 所以可以用00XX100作为modrm引导出sib 然后裸用sib来编码[GPR]这种寻址模式
比如mov eax,[ebx] 既可以只用modrm来编码 8B 03
也可以通过sib来编码8B 04 63 只不多后面这种太蛋疼了
注意这里的scale字段 特意设置成01 实际上无所谓的 就算是 8B 04 E3 也是一样的mov eax,[ebx] 所以我们在这里说 如果index为100 则视scale为0
|
能力值:
( LV2,RANK:10 )
|
-
-
9 楼
好贴,mark
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
最喜欢看雪里的讨论氛围了。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
是很多都没见过!多些LZ分享哈
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
分析的太精细了。佩服。
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
同感啊。。特别是对初级会员
|
|
|