搜档网
当前位置:搜档网 › Linux基本反汇编结构与GDB入门

Linux基本反汇编结构与GDB入门

Linux基本反汇编结构与GDB入门
Linux基本反汇编结构与GDB入门

Linux下的汇编与Windows汇编最大的不同就是第一个操作数是原操作数,第二个是目的操作数,而Windows下却是相反。

1、基本操作指令

简单的操作数类型说明,一般有三种,

(1)立即数操作数,也就是常数值。立即数的书写方式是“$”后面跟一个整数,比如$0x1F,这个会在后面的具体分析中见到很多。

(2)寄存器操作数,它表示某个寄存器的内容,用符号Ea来表示任意寄存器a,用引用R[Ea]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器表示符作为索引。

(3)操作数是存储器引用,它会根据计算出来的地址(通常称为有效地址)访问某个存储器位置。用符号Mb[Addr]表示对存储在存储器中从地址Addr开始的b字节值的引用。通常可以省略下标b。

图1表示有多种不同的寻址模式,一个立即数偏移Imm,一个基址寄存器Eb,一个变址或索引寄存器Ei和一个伸缩因子s。有效地址被计算为Imm+R[Eb]+R[Ei]*s,对于这中寻址方式,我们可以在数组或者结构体中进行对元

注:操作数可以是立即数值、寄存器值或是来自存储器的值,伸缩因子必须是1、2、4、或者是8。从上面的图我们就可以大致了解操作数的类型了。

在操作指令中,最频繁使用的指令是执行数据传送的指令。对于传送指令的两个操作数不能都指向存储器位置(我的理解是一般存储器存储的都是地址,不能够对地址和地址进行操作)。将一个值从一个存储器位置拷到另一个存储器位置需要两条指令——第一条指令将源值加载到寄存器中,第二条将该寄存器值写入到目的位置。下面给出源操作数和目的操作数的五种可能组合。

1、movl $0x4050, %eax 立即数——寄存器

2、movl %ebp, %esp 寄存器——寄存器

3、movl (%edi, %ecx), %eax 存储器——寄存器

4、movl $-17, (%esp) 立即数——存储器

5、movl %eax, -12(%ebp) 寄存器——存储器

注意这里的指令mov可能有不同的形式,不同平台的汇编一般是有些不一样的,

结合例子来进行讲解一下指令的具体操作,在这里将会正式接触到Linux下的GCC开发环境和GDB调试器,不过都是比较简单的应用。我的Linux操作系统是Ubuntu9.10,其它版本的差别应该不大,

如果我们要编写一个程序,我们可以用Linux下自带的vi或vim编辑器,studyrush@studyrush-desktop:~/C$ vi exchange.c

vi 后面加我们要创建的程序文件的名字,在这里是exchange.c

studyrush@studyrush-desktop:~/C$ gcc -o exchange exchange.c

gcc -o exchange exchange.c 或gcc exchange –o exchange这两者都可以对源文件进行编译,-o exchange 表示对我们要输出的文件名称,可能表达的不够准确,大家可以先熟悉一下gcc编译器,应该就会明白的了。

studyrush@studyrush-desktop:~/C$ ./exchange 点加斜线再加输出文件名就表示运行程序,下面是运行的结果。

a = 3,

b = 4

使用GDB可以参考附件里面的教程,这份教程写的很不错,看雪论坛本身也有,大家可以看这个贴(https://www.sodocs.net/doc/293943497.html,/showthread.php?t=77746),现在我只是把它放在附件里面。

studyrush@studyrush-desktop:~/C$ gdb exchange

命令disas就表示反汇编(disassembly),后面再加上要显示的函数名,我们就可以看到函数对应的反汇编代码了。

(gdb) disas exchange

Dump of assembler code for function exchange:

0x080483c4 : push %ebp

0x080483c5 : mov %esp,%ebp

0x080483c7 : sub $0x10,%esp

0x080483ca : mov 0x8(%ebp),%eax

0x080483cd : mov (%eax),%eax

0x080483cf : mov %eax,-0x4(%ebp)

0x080483d2 : mov 0x8(%ebp),%edx

0x080483d5 : mov 0xc(%ebp),%eax

0x080483d8 : mov %eax,(%edx)

0x080483da : mov -0x4(%ebp),%eax

0x080483dd : leave

0x080483de : ret

End of assembler dump.

进一步来分析上面的反汇编代码,这里的代码可能与前面的讲的指令操作有一些不同,因为这是很正常的,不同的操作系统应该有所差别,这也是汇编语言一般与平台有关,移植性并不好。

push %ebp

mov %esp,%ebp

sub $0x10,%esp

对有过反汇编的人对上面的代码肯定不会陌生,这里就是将ebp进栈,保存esp 的值,并为局部变量预留空间。要记得源操作数与目的操作数的位置,前面有讲的。这里也一定程度对C语言中的指针使用进行了说明。看源代码可以知道。mov 0x8(%ebp),%eax

mov (%eax),%eax

mov %eax,-0x4(%ebp)

mov 0x8(%ebp),%eax 取得xp,其实是指针本身,即是地址,汇编表示即可为mov %ebp + 8, %eax,这里就是存储器——寄存器的操作方式。

mov (%eax),%eax 这里是取得指针指向的值,即*xp,(%eax)表示取%eax 中的地址指向的值,比如

寄存器值地址值

%eax 0x100 0x100 0xFF

(%eax)的值就是0xFF了。

mov %eax,-0x4(%ebp) 这里是将值赋给局部变量,局部变量是在ebp的上面的,表示其地址比ebp的地址要小。

mov 0x8(%ebp),%edx

mov 0xc(%ebp),%eax

mov %eax,(%edx)

这里与上面的分析类似,并没有出现局部变量,可以表明这里是函数参数在进行交换。这里的操作数方式是寄存器——存储器

mov -0x4(%ebp),%eax 通过寄存器eax将值返回,记住一般函数的返回值都是通过eax寄存器返回的。

0x080483dd : leave

0x080483de : ret 函数返回

分析完反汇编代码之后有没有看出来函数调用是采用哪种调用约定呢?其实就是C调用方式(__cdecl)的方式。

//程序exchange.c,表示交换两个数。

#include

#include

int exchange(int *xp, int y)

{

int x = *xp;

*xp = y;

return (x);

}

int main()

{

int a = 4;

int b = exchange(&a, 3);

printf("a = %d, b = %d\n", a, b);

return 0;

}

通过上面的学习我们可以明白其实C语言中的指针本质上就是地址。抓住这一点我们对指针的理解就会更加明白。当然复杂的指针操作还是要在实践之中慢慢的掌握。

2、算术和逻辑操作

加载有效地址(Load Effective Address)指令lea实际上是mov指令的变形,因为mov不能够直接对两个存储器操作数,,指令将有效地址写入到目的操作数(如寄存器)。举个例子:

如果寄存器%edx的值为x,那么指令lea 7(%edx, %edx, 4), %eax将设置寄存

注:后缀l表示对双字进行操作,还可以为w和b分别表示字和字节。

练习一下下面的移位操作指令

#include

int shiftlr(int x, int n)

{

x <<= 2;

x >>= n;

return x;

}

int main()

{

int a = 4, b = 3;

int ans = shiftlr(a, b);

printf("%d\n", ans);

return 0;

}

shiftlr函数反汇编代码:

0x080483c4 : push %ebp

0x080483c5 : mov %esp,%ebp

0x080483c7 : shll $0x2,0x8(%ebp)

0x080483cb : mov 0xc(%ebp),%ecx

0x080483ce : sarl %cl,0x8(%ebp)

0x080483d1 : mov 0x8(%ebp),%eax

0x080483d4 : pop %ebp

0x080483d5 : ret

从上面的代码我们可以看到,移位量用单个字节编码,因为只允许进行0到31位的移位。位移量可以是一个立即数,或者放在单字节寄存器元素%cl中。

给个例子和其相应的反汇编代码练习一下。

#include

int main()

{

int a = 6, b = 3;

unsigned int c = 10, d = 2;

int ans1 = a / b;

unsigned int ans2 = c * d;

return 0;

}

0x08048394 : lea 0x4(%esp),%ecx

0x08048398 : and $0xfffffff0,%esp

0x0804839b : pushl -0x4(%ecx)

0x0804839e : push %ebp

0x0804839f : mov %esp,%ebp

0x080483a1 : push %ecx

0x080483a2 : sub $0x28,%esp

0x080483a5 : movl $0x6,-0x8(%ebp)

0x080483ac : movl $0x3,-0xc(%ebp)

0x080483b3 : movl $0xa,-0x10(%ebp)

0x080483ba : movl $0x2,-0x14(%ebp)

0x080483c1 : mov -0x8(%ebp),%eax

0x080483c4 : mov %eax,-0x2c(%ebp)

0x080483c7 : mov -0x2c(%ebp),%edx

0x080483ca : mov %edx,%eax

0x080483cc : sar $0x1f,%edx

0x080483cf : idivl -0xc(%ebp)

0x080483d2 : mov %eax,-0x18(%ebp)

0x080483d5 : mov -0x10(%ebp),%eax

0x080483d8 : imul -0x14(%ebp),%eax

0x080483dc : mov %eax,-0x1c(%ebp)

0x080483df : mov $0x0,%eax

0x080483e4 : add $0x28,%esp

0x080483e7 : pop %ecx

0x080483e8 : pop %ebp

0x080483e9 : lea -0x4(%ecx),%esp

0x080483ec : ret

2、控制结构

CF:进位标志。最近的操作使最高位产生了进位,它可用来检查无符号操作数的溢出。

ZF:零标志。最近的操作得出的结果为0。

SF:符号标志。最近的操作得到的结果为负数。

OF:溢出标志。最近的操作导致一个二进制补码溢出——正溢出或负溢出。

整型变量a、b和t,用add指令完成等价于C表达式t = a + b的功能。会根据下面的表达式来设置条件码:

CF:(unsigned t) < (unsigned a) 无符号溢出

ZF: (t == 0) 零

SF: (t < 0) 负数

OF: (a < 0 == b < 0) && (t < 0 != a < 0) 有符号溢出

lea指令不改变任何条件码,因为它是用来进行地址计算的。

cmpb、cmpw、cmpl指令根据它们的两个操作数之差来设置条件码。

testb、testw、testl指令会根据它们的两个操作数的与(AND)来设置零标志和负数标志。

每条指令根据条件码的某个组合,将一个字节设置为0或者1。有些指令有“同义名”,也就是,同一条机器指令有别的名字

结合上面的说明练习一下。

#include

char ctest(int a, int b, int c)

{

char t1 = a < b;

char t2 = b < (unsigned)a;

char t3 = (short)c >= (short)a;

char t4 = (char)a != (char)c;

char t5 = c > b;

char t6 = a > 0;

int sum = t1 + t2 + t3 + t4 + t5 + t6;

return sum;

}

int main()

{

int x = 5, y = 6, z = 7;

int ans = ctest(x, y, z);

printf("%d\n", ans);

return 0;

}

(gdb) disas ctest

0x080483c4 : push %ebp

0x080483c5 : mov %esp,%ebp

0x080483c7 : sub $0x10,%esp

0x080483ca : mov 0x8(%ebp),%eax 0x080483cd : cmp 0xc(%ebp),%eax 0x080483d0 : setl %al

0x080483d3 : mov %al,-0x1(%ebp) 0x080483d6 : mov 0xc(%ebp),%edx 0x080483d9 : mov 0x8(%ebp),%eax 0x080483dc : cmp %eax,%edx

0x080483de : setb %al

0x080483e1 : mov %al,-0x2(%ebp) 0x080483e4 : mov 0x10(%ebp),%eax 0x080483e7 : mov %eax,%edx

0x080483e9 : mov 0x8(%ebp),%eax 0x080483ec : cmp %ax,%dx

0x080483ef : setge %al

0x080483f2 : mov %al,-0x3(%ebp) 0x080483f5 : mov 0x8(%ebp),%eax 0x080483f8 : mov %eax,%edx

0x080483fa : mov 0x10(%ebp),%eax 0x080483fd : cmp %al,%dl

0x080483ff : setne %al

0x08048402 : mov %al,-0x4(%ebp) 0x08048405 : mov 0x10(%ebp),%eax 0x08048408 : cmp 0xc(%ebp),%eax 0x0804840b : setg %al

0x0804840e : mov %al,-0x5(%ebp) 0x08048411 : cmpl $0x0,0x8(%ebp) 0x08048415 : setg %al

0x08048418 : mov %al,-0x6(%ebp) 0x0804841b : movsbl -0x1(%ebp),%edx 0x0804841f : movsbl -0x2(%ebp),%eax 0x08048423 : add %eax,%edx

0x08048425 : movsbl -0x3(%ebp),%eax

0x08048429 : add %eax,%edx

0x0804842b : movsbl -0x4(%ebp),%eax

0x0804842f : add %eax,%edx

0x08048431 : movsbl -0x5(%ebp),%eax

0x08048435 : add %eax,%edx

0x08048437 : movsbl -0x6(%ebp),%eax

0x0804843b : lea (%edx,%eax,1),%eax

0x0804843e : mov %eax,-0xc(%ebp)

0x08048441 : mov -0xc(%ebp),%eax

0x08048444 : leave

0x08048445 : ret

jmp指令是无条件跳转,它可以是直接跳转,即跳转目标是作为指令的一部分编码的,也可以是间接跳转,即跳转目标是从寄存器或存储器位置中读出的。看下面的两条指令:

jmp *%eax 用寄存器%eax中的值作为跳转目标。

jmp *(%eax) 以%eax中的值作为读地址,从存储器中读出跳转目标。

跳转指令有几种不同的编码,但是最常用的一些事PC相关的,也就是,它们会将目标指令的地址与紧跟在跳转指令后面那条指令的地址之间的差作为编码。这些地址偏移量可以编码为一、二或四个字节。第二种编码方法是给出“绝对”地址,用四个字节直接指定目标。

下面给出具体的例子进行一些分析,动手实践是必须要的,在计算机这一块中编程能力还是第一位的,这个也关系到自己以后职业的定位和发展。大家勤加练习,我也正在努力中。

C中的if-else语句的通用形式是这样的:

if (test-expr)

thenstatement

else

else-statement

这里test-expr是一个整数表达式,它的取值为0(解释为“假”)或者为非0(解释为“真”),两个分支语句(then-statement和else-statement)只会执行一个。#include

#include

using namespace std;

int absdiff(int x, int y)

{

if (x < y)

return y - x;

else

return x - y;

}

int main()

{

int m = 5, n = 6;

int ans = 0;

ans = absdiff(m, n);

printf("%d\n", ans);

return 0;

}

0x080485a4 <_Z7absdiffii+0>: push %ebp

0x080485a5 <_Z7absdiffii+1>: mov %esp,%ebp

0x080485a7 <_Z7absdiffii+3>: sub $0x4,%esp

0x080485aa <_Z7absdiffii+6>: mov 0x8(%ebp),%eax

0x080485ad <_Z7absdiffii+9>: cmp 0xc(%ebp),%eax

0x080485b0 <_Z7absdiffii+12>: jge 0x80485c1 <_Z7absdiffii+29>

0x080485b2 <_Z7absdiffii+14>: mov 0x8(%ebp),%edx

0x080485b5 <_Z7absdiffii+17>: mov 0xc(%ebp),%eax

0x080485b8 <_Z7absdiffii+20>: mov %eax,%ecx

0x080485ba <_Z7absdiffii+22>: sub %edx,%ecx

0x080485bc <_Z7absdiffii+24>: mov %ecx,-0x4(%ebp)

0x080485bf <_Z7absdiffii+27>: jmp 0x80485ce <_Z7absdiffii+42>

0x080485c1 <_Z7absdiffii+29>: mov 0xc(%ebp),%edx

0x080485c4 <_Z7absdiffii+32>: mov 0x8(%ebp),%eax

0x080485c7 <_Z7absdiffii+35>: mov %eax,%ecx

0x080485c9 <_Z7absdiffii+37>: sub %edx,%ecx

0x080485cb <_Z7absdiffii+39>: mov %ecx,-0x4(%ebp)

0x080485ce <_Z7absdiffii+42>: mov -0x4(%ebp),%eax

0x080485d1 <_Z7absdiffii+45>: leave

0x080485d2 <_Z7absdiffii+46>: ret

cmp 0xc(%ebp),%eax

jge 0x80485c1 <_Z7absdiffii+29>

mov 0x8(%ebp),%edx

mov -0x4(%ebp),%eax

从上面的三句我们可以看出这里就是执行if条件语句了。也可以看出if条件语句反汇编后的一些特征,我们一般可以认为cmp+条件跳转指令+jmp跳转,就是if 条件语句反汇编的代码。这对于我们在实际中分析代码需要快速识别一些特征反汇编代码很有帮助。也方便我们对于代码的整体结构有更好的认识,记住一些常用的特征代码结构是必要的,这些也可以从正面入手,再反面进行分析,从而可以提高快速分析汇编代码的能力。

mov 0x8(%ebp),%edx 取得x

mov 0xc(%ebp),%eax 取得y

mov %eax,%ecx 把y放入寄存器%ecx中

sub %edx,%ecx 得到x – y

mov %ecx,-0x4(%ebp)

mov -0x4(%ebp),%eax 将结果放入%eax中返回

由于上面的跳转指令是jge即表示大于等于跳转,而if条件语句本身的比较是用<进行的,所以上面这段汇编代码是先进行else后面的语句体进行执行的。对代码进行分析即可以知道。另外一般函数的返回值都是用%eax寄存器返回的,看最后一句就可以知道了。

C语言提供了好几种循环结构,即while、for和do-while。汇编语言中并没有相应的指令存在,作为替代,将条件测试和跳转组合起来实现循环的效果。比较有趣的是,大多数汇编器根据一个循环的do-while形式来产生循环代码。

do-while循环

其通用形式是这样的:

do

body-statement

while (test-expr);

循环的效果就是重复执行body-statement,对test-expr求值,如果求值的结果为非零,就继续循环。注意,body-statement至少执行一次。

看看下面举的例子来进行分析。

#include

#include

using namespace std;

int fib_dw(int n)

{

int i = 0;

int val = 0;

int nval = 1;

do {

int t = val + nval;

val = nval;

nval = t;

i++;

} while ( i < n);

return val;

}

int main()

{

int m = 5;

int ans = 0;

ans = fib_dw(m);

printf("%d\n", ans);

return 0;

}

0x080485a4 <_Z6fib_dwi+0>: push %ebp

0x080485a5 <_Z6fib_dwi+1>: mov %esp,%ebp

0x080485a7 <_Z6fib_dwi+3>: sub $0x10,%esp

0x080485aa <_Z6fib_dwi+6>: movl $0x0,-0x4(%ebp) 0x080485b1 <_Z6fib_dwi+13>: movl $0x0,-0x8(%ebp) 0x080485b8 <_Z6fib_dwi+20>: movl $0x1,-0xc(%ebp) 0x080485bf <_Z6fib_dwi+27>: mov -0xc(%ebp),%edx 0x080485c2 <_Z6fib_dwi+30>: mov -0x8(%ebp),%eax 0x080485c5 <_Z6fib_dwi+33>: add %edx,%eax

0x080485c7 <_Z6fib_dwi+35>: mov %eax,-0x10(%ebp) 0x080485ca <_Z6fib_dwi+38>: mov -0xc(%ebp),%eax 0x080485cd <_Z6fib_dwi+41>: mov %eax,-0x8(%ebp) 0x080485d0 <_Z6fib_dwi+44>: mov -0x10(%ebp),%eax 0x080485d3 <_Z6fib_dwi+47>: mov %eax,-0xc(%ebp) 0x080485d6 <_Z6fib_dwi+50>: addl $0x1,-0x4(%ebp)

0x080485da <_Z6fib_dwi+54>: mov -0x4(%ebp),%eax

0x080485dd <_Z6fib_dwi+57>: cmp 0x8(%ebp),%eax

0x080485e0 <_Z6fib_dwi+60>: jl 0x80485bf <_Z6fib_dwi+27>

0x080485e2 <_Z6fib_dwi+62>: mov -0x8(%ebp),%eax

0x080485e5 <_Z6fib_dwi+65>: leave

0x080485e6 <_Z6fib_dwi+66>: ret

这段代码就是while语句括号进行的条件比较,

0x080485da <_Z6fib_dwi+54>: mov -0x4(%ebp),%eax

0x080485dd <_Z6fib_dwi+57>: cmp 0x8(%ebp),%eax

0x080485e0 <_Z6fib_dwi+60>: jl 0x80485bf <_Z6fib_dwi+27>

先将局部变量i的值放入到%eax寄存器中,再与传进来的参数n进行比较,如果小于则进行跳转,我们可以看出while条件语句的反汇编后的特征结构为cmp+条件跳转语句。这也一定程度说明了do-while这种循环结构反汇编后的代码比较少,不知道效率是否有一定的提高,对一些优化可以进行实践操作。

while循环的通用形式是这样的:

while (test-expr)

body-statement

它与do-while的不同之处在于对test-expr求值,在第一次执行body-statement 之前,循环就可能中止了。

#include

#include

using namespace std;

int loop_while(int a, int b)

{

int i = 0;

int result = a;

while (i < 256)

{

result += a;

a -= b;

i += b;

}

return result;

}

int main()

{

int n = 5, m = 6;

int ans = 0;

ans = loop_while(n, m);

printf("%d\n", ans);

return 0;

}

0x080485a4 <_Z10loop_whileii+0>: push %ebp

0x080485a5 <_Z10loop_whileii+1>: mov %esp,%ebp

0x080485a7 <_Z10loop_whileii+3>: sub $0x10,%esp

0x080485aa <_Z10loop_whileii+6>: movl $0x0,-0x4(%ebp)

0x080485b1 <_Z10loop_whileii+13>: mov 0x8(%ebp),%eax

0x080485b4 <_Z10loop_whileii+16>: mov %eax,-0x8(%ebp)

0x080485b7 <_Z10loop_whileii+19>: jmp 0x80485cb <_Z10loop_whileii+39>

0x080485b9 <_Z10loop_whileii+21>: mov 0x8(%ebp),%eax

0x080485bc <_Z10loop_whileii+24>: add %eax,-0x8(%ebp)

0x080485bf <_Z10loop_whileii+27>: mov 0xc(%ebp),%eax

0x080485c2 <_Z10loop_whileii+30>: sub %eax,0x8(%ebp)

0x080485c5 <_Z10loop_whileii+33>: mov 0xc(%ebp),%eax

0x080485c8 <_Z10loop_whileii+36>: add %eax,-0x4(%ebp)

0x080485cb <_Z10loop_whileii+39>: cmpl $0xff,-0x4(%ebp)

0x080485d2 <_Z10loop_whileii+46>: jle 0x80485b9 <_Z10loop_whileii+21>

0x080485d4 <_Z10loop_whileii+48>: mov -0x8(%ebp),%eax

0x080485d7 <_Z10loop_whileii+51>: leave

0x080485d8 <_Z10loop_whileii+52>: ret

上面红色的红色标记就是while条件语句反汇编后的特征结构,从正向出发,再从逆向来分析语言的一些机制对于我们更好的理解一些语言机制的实现编译器在背后实现了一些什么,这些大部分可以从反汇编后的代码看出。

for循环的通用形式:

for (init-expr; test-expr; update-expr)

body-statement

C语言标准说明,这样一个循环的行为与下面这段使用while循环的代码的行为一样:

init-expr

while (test-expr) {

body-statement

update-expr;

}

程序首先会对初始化表达式init-expr求值。然后进行循环,它会先对测试条件test-expr求值,如果测试结果为“假”就会退出,然后执行循环体body-statement,最后对更新表达式update-expr求值。

#include

#include

using namespace std;

int fib_for(int n)

{

int i;

int val = 1;

int nval = 1;

for (i = 1; i < n; ++i)

{

int t = val + nval;

val = nval;

nval = t;

}

return val;

}

int main()

{

int a = 5;

int ans = 0;

ans = fib_for(a);

printf("%d\n", ans);

return 0;

}

0x080485a4 <_Z7fib_fori+0>: push %ebp

0x080485a5 <_Z7fib_fori+1>: mov %esp,%ebp

0x080485a7 <_Z7fib_fori+3>: sub $0x10,%esp

0x080485aa <_Z7fib_fori+6>: movl $0x1,-0x8(%ebp)

0x080485b1 <_Z7fib_fori+13>: movl $0x1,-0xc(%ebp)

0x080485b8 <_Z7fib_fori+20>: movl $0x1,-0x4(%ebp)

0x080485bf <_Z7fib_fori+27>: jmp 0x80485dc <_Z7fib_fori+56> 0x080485c1 <_Z7fib_fori+29>: mov -0xc(%ebp),%edx

0x080485c4 <_Z7fib_fori+32>: mov -0x8(%ebp),%eax

0x080485c7 <_Z7fib_fori+35>: add %edx,%eax

0x080485c9 <_Z7fib_fori+37>: mov %eax,-0x10(%ebp)

0x080485cc <_Z7fib_fori+40>: mov -0xc(%ebp),%eax

0x080485cf <_Z7fib_fori+43>: mov %eax,-0x8(%ebp)

0x080485d2 <_Z7fib_fori+46>: mov -0x10(%ebp),%eax

0x080485d5 <_Z7fib_fori+49>: mov %eax,-0xc(%ebp)

0x080485d8 <_Z7fib_fori+52>: addl $0x1,-0x4(%ebp)

0x080485dc <_Z7fib_fori+56>: mov -0x4(%ebp),%eax

0x080485df <_Z7fib_fori+59>: cmp 0x8(%ebp),%eax

0x080485e2 <_Z7fib_fori+62>: jl 0x80485c1 <_Z7fib_fori+29>

0x080485e4 <_Z7fib_fori+64>: mov -0x8(%ebp),%eax

0x080485e7 <_Z7fib_fori+67>: leave

这里的反汇编代码结构与上面的while条件语句是一样的,也表明在高级语言的不同形式语句在底层的表现有可能是一样的或是以相似的方式的来实现的。

switch语句提供了根据一个整数索引值进行多重分支的能力,相比起用很长的if-else语句,使用跳转表的优点是执行开关语句的时间和开关情况的数量无关。这样不仅提高了C代码的可读性,而且通过使用一种称为跳转表的数据结构使得实现更加高效。跳转表是一个数组,表项i是一个代码段的地址,这个代码段实现的是当开关索引值等于i时程序应该采取的动作。下面给个程序来个感性的认识。

int switch_eg(int x)

{

int result = x;

switch (x)

{

case 100:

result *= 13;

break;

case 102:

result += 10;

break;

case 103:

result += 11;

break;

case 104:

case 106:

result *= result;

break;

default:

result = 0;

}

对于上面的代码还是有一定参考性的,从代码风格来讲或者规范我们都必须在每一个case后面加上一个break语句,不然就显得你对语言还不是很熟悉或者没有注意代码规范这一块,其实这些对于公司来说还是挺重要的。下面来看看具体的反汇编代码吧。

0x080483f4 : push %ebp

0x080483f5 : mov %esp,%ebp

0x080483f7 : sub $0x14,%esp

0x080483fa : mov 0x8(%ebp),%eax

0x080483fd : mov %eax,-0x4(%ebp)

0x08048400 : mov 0x8(%ebp),%eax

0x08048403 : sub $0x64,%eax

0x08048406 : mov %eax,-0x14(%ebp)

0x08048409 : cmpl $0x6,-0x14(%ebp)

0x0804840d : ja 0x8048447

0x0804840f : mov -0x14(%ebp),%edx

0x08048412 : mov 0x8048570(,%edx,4),%eax

0x08048419 : jmp *%eax

0x0804841b : mov -0x4(%ebp),%eax

0x0804841e : mov %eax,%edx

0x08048420 : add %edx,%edx

0x08048422 : add %eax,%edx

0x08048424 : shl $0x2,%edx

0x08048427 : lea (%edx,%eax,1),%eax

0x0804842a : mov %eax,-0x4(%ebp)

0x0804842d : jmp 0x804844e

0x0804842f : addl $0xa,-0x4(%ebp)

0x08048433 : jmp 0x804844e

0x08048435 : addl $0xb,-0x4(%ebp)

0x08048439 : jmp 0x804844e

0x0804843b : mov -0x4(%ebp),%eax

0x0804843e : imul -0x4(%ebp),%eax

0x08048442 : mov %eax,-0x4(%ebp)

0x08048445 : jmp 0x804844e

0x08048447 : movl $0x0,-0x4(%ebp)

0x0804844e : mov -0x4(%ebp),%eax

0x08048451 : leave

0x08048452 : ret

对于上面的反汇编代码,我们可以从中看出有比较多的无条件跳转时,可以猜测这里有switch条件语句,在实际分析中需要有大胆的猜测加上详细的分析就可以得到自己想要分析的汇编代码的整体逻辑结构,从而能够写出相似功能的源代码。

总结:

如果可以最好能够结合《深入理解计算机系统》这本书来看,已经有第二版了,其实我也是学习这本书记录的学习笔记。这本书的价值就不用我说了五星书,必须看的。

Linu系统编程实验二gccgdb的使用以及Makefile文件的编写

实验二:gcc、gdb、Makefile的使用 实验目的: (一)学会使用gcc编译器 (二)学会gdb调试器的使用 (三)学会编写Makefile 实验要求: (一)编写一应用程序,使用gcc进行编译,并分别使用-o,-g,-static,-O2等选项(二)编写一应用程序,使用gdb调试,调试中使用到该小节所介绍的所有命令 (三)实现一应用程序,该程序有两个c文件构成,使用makefile来完成对该程序的编译实验器材: 软件:安装了Linux的vmware虚拟机 硬件:PC机一台 实验步骤: (一)gcc编译器 1、先用vi编辑文件,内容如下: 2、gcc指令的一般格式为:gcc [选项] 要编译的文件 [选项] [目标文件] 例:使用gcc编译命令,编译生成可执行文件hello,并运行hello 上面的命令一步由.c文件生成了可执行文件,将gcc的四个编译流程:预处理、编译、汇编、连接一步完成,下面将介绍四个流程分别做了什么工作 3、-E选项的作用:只进行预处理,不做其他处理。 例:只对文件进行预处理,生成文件,并查看 通过查看可以看到头文件包含部分代码#include <>经过预处理阶段之后,编译器已将的内容贴了进来。 4、-S选项的使用 -S选项的作用:只是编译不汇编,生成汇编代码

例:将文件只进行编译而不进行汇编,生成汇编代码 5、-c选项的使用 -c选项的作用:只是编译不连接,生成目标文件.o 例:将汇编代码只编译不链接成文件 6、将编译好的链接库,生成可执行文件hello 7、-static选项的使用 -static选项的作用:链接静态库 例:比较连接动态库生成的可执行文件hello和链接静态库生成的可执行文件hello1的大小 可以看到静态链接库的可执行文件hello1比动态链接库的可执行文件hello要大的多,他们的执行效果是一样的 8、-g选项的使用 -g选项的作用:在可执行程序中包含标准调试信息 例:将编译成包含标准调试信息的可执行文件hello2

汇编语言 快速入门

“哎哟,哥们儿,还捣鼓汇编呢?那东西没用,兄弟用VB"钓"一个API就够你忙活个十天半月的,还不一定搞出来。”此君之言倒也不虚,那吾等还有无必要研他一究呢?(废话,当然有啦!要不然你写这篇文章干嘛。)别急,别急,让我把这个中原委慢慢道来:一、所有电脑语言写出的程序运行时在内存中都以机器码方式存储,机器码可以被比较准确的翻译成汇编语言,这是因为汇编语言兼容性最好,故几乎所有跟踪、调试工具(包括WIN95/98下)都是以汇编示人的,如果阁下对CRACK颇感兴趣……;二、汇编直接与硬件打交道,如果你想搞通程序在执行时在电脑中的来龙去脉,也就是搞清电脑每个组成部分究竟在干什么、究竟怎么干?一个真正的硬件发烧友,不懂这些可不行。三、如今玩DOS的多是“高手”,如能像吾一样混入(我不是高手)“高手”内部,不仅可以从“高手”朋友那儿套些黑客级“机密”,还可以自诩“高手”尽情享受强烈的虚荣感--#$%&“醒醒!” 对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?――Here we go!(阅读时看不懂不要紧,下文必有分解) 因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) CPU是可以执行电脑所有算术╱逻辑运算与基本I/O控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指

GDB基本使用方法

GDB基本使用方法 GDB是用来调试用户态程序的一款工具,可以追踪程序运行轨迹,打出调用栈,寄存器内容,查看内存等等 首先在编译时,我们必须要把调试信息加到可执行文件中。使用编译器(cc/gcc/g++)的-g 参数可以做到这一点。如果没有-g,你将看不见程序的函数名、变量名,所代替的全是运行时的内存地址。 启动GDB 直接找到gdb的路径执行就ok,进入GDB后可以输入help命令查看帮助信息 加载可执行文件启动 gdb executable-file set args 参数列表 以上两步等同于 gdb –args executable-file 参数列表 run或者start都可以启动调试 多用于调试启动阶段就异常的程序 调试正在运行的程序 以下三种形式都可以attach到正在运行的程序上调试 ps -ef | grep http www-data 24470 1 0 Jan17 ? 00:00:14 /usr/sbin/lighttpd gdb attach 24470 gdb --pid 24470 gdb -p 24470 设置断点 break -- Set breakpoint at specified line or function b func1 break func1 设置在func1处 b file:line 设置在文件的第几行处 b *0x指令地址设置在具体的某条汇编指令处 设置断点后,代码执行到func1处会被断住,方便我们查看当时的信息 打印调用栈 backtrace bt 如果你要查看栈下面层的详细信息 frame 栈中的层编号 查看所有断点 info break 删除断点 delete 断点号 如果不加断点号为删除全部断点 禁用断点 disable 断点号 启用断点

软件破解入门教程

先教大家一些基础知识,学习破解其实是要和程序打交道的,汇编是破解程序的必备知识,但有可能部分朋友都没有学习过汇编语言,所以我就在这里叫大家一些简单实用的破解语句吧! ---------------------------------------------------------------------------------------------------------------- 语句:cmp a,b //cmp是比较的意思!在这里假如a=1,b=2 那么就是a与b比较大小. mov a,b //mov是赋值语句,把b的值赋给a. je/jz //就是相等就到指定位置(也叫跳转). jne/jnz //不相等就到指定位置. jmp //无条件跳转. jl/jb //若小于就跳. ja/jg //若大于就跳. jge //若大于等于就跳. 这里以一款LRC傻瓜编辑器为例,讲解一下软件的初步破解过程。大家只要认真看我的操作一定会!假如还是不明白的话提出难点帮你解决,还不行的话直接找我!有时间给你补节课!呵呵! 目标:LRC傻瓜编辑器杀杀杀~~~~~~~~~ 简介:本软件可以让你听完一首MP3歌曲,便可编辑完成一首LRC歌词。并且本软件自身还带有MP3音乐播放和LRC歌词播放功能,没注册的软件只能使用15天。 工具/原料 我们破解或给软件脱壳最常用的软件就是OD全名叫Ollydbg,界面如图: 它是一个功能很强大的工具,左上角是cpu窗口,分别是地址,机器码,汇编代码,注释;注释添加方便,而且还能即时显示函数的调用结果,返回值. 右上角是寄存器窗口,但不仅仅反映寄存器的状况,还有好多东东;双击即可改变Eflag的值,对于寄存器,指令执行后发生改变的寄存器会用红色突出显示. cpu窗口下面还有一个小窗口,显示当前操作改变的寄存器状态. 左下角是内存窗口.可以ascii或者unicode两种方式显示内存信息. 右下角的是当前堆栈情况,还有注释啊. 步骤/方法 1. 我们要想破解一个软件就是修改它的代码,我们要想在这代码的海洋里找到我们破解关键的代码确实很棘 手,所以我们必须找到一定的线索,一便我们顺藤摸瓜的找到我们想要的东东,现在的关键问题就是什么

实例—使用gdb调试器

2.4 实例—使用gdb调试器 1.编写实例程序gcctest.c,见2.2小节的开头部分 2.编译 3.启动GDB,执行程序 启动gdb,进入gdb调试环境,可以使用gdb的命令对程序进行调试。 [root@localhost gdbtest txt]# gdb //启动gdb GNU gdb Fedora (6.8-27.el5) Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu". (gdb) run gcctest //在gdb中,运行程序使用r或是run命令,注意,gcctest没有调试信息Starting program: gcctest No executable file specified. Use the "file" or "exec-file" command. //要使用file或exec-file命令指出要运行的程序 (gdb) file gcctest //使用file命令指出要运行的程序gcctest,注意,对gdb命令也可以使用Tab gcctest gcctest.c gcctestg (gdb) file gcctest //使用file命令指出要运行的程序gcctest Reading symbols from /root/Desktop/gdbtest txt/gcctest...(no debugging symbols found)...done. (gdb) r //在gdb中,运行程序使用r或是run命令 Starting program: /root/Desktop/gdbtest txt/gcctest gcctest (no debugging symbols found) (no debugging symbols found) (no debugging symbols found) hello in main hello 1 hello 2 sum=54125560035401396161080590579269632.000000 Program exited with code 057. (gdb) file gcctestg //使用file命令指出要运行的程序gcctestg Reading symbols from /root/Desktop/gdbtest txt/gcctestg...done. (gdb) r //在gdb中,运行程序使用r或是run命令 Starting program: /root/Desktop/gdbtest txt/gcctestg gcctest hello in main hello 1 hello 2 sum=54125560035401396161080590579269632.000000 Program exited with code 057. (gdb) q //使用q或是quit命令退出gdb [root@localhost gdbtest txt]# 4.GDB命令简介

Linu系统编程实验gccgdb的使用以及Makefile文件的编写

实验二:gcc 、gdb 、Makefile 的使用 实验目的: (一) 学会使用gcc 编译器 (二) 学会gdb 调试器的使用 (三) 学会编写 Makefile 实验要求: (一) 编写一应用程序,使用 gcc 进行编译,并分别使用-o ,-g ,-static ,-02等选项 (二) 编写一应用程序,使用 gdb 调试,调试中使用到该小节所介绍的所 有命令 (三) 实现一应用程序,该程序有两个 c 文件构成,使用 makefile 来完成对该程序的编译 实验器材: 软件:安装了 Linux 的vmware 虚拟机 硬件:PC 机一台 实验步骤: (一) gcc 编译器 1先用vi 编辑hello.c 文件,内容如下: #include int main(void) { priritf("hello world\n"); return 0; } 2、gcc 指令的一般格式为:gcc [选项]要编译的文件[选项][目标文件] 例:使用gcc 编译命令,编译 hello.c 生成可执行文件 hello ,并运行hello gcc]# vi hello ? c gcc]# gcc hello.c -o hello gcc]# ./hello 上面的命令一步由.c 文件生成了可执行文件,将 gcc 的四个编译 流程:预处理、编译、 汇编、连接一步完成,下面将介绍四个流程分别做了什么工作 3、 -E 选项的作用:只进行预处理,不做其他处理。 例:只对hello.c 文件进行预处理,生成文件 hello.i ,并查看 [root@locdlhost gcc ]# gcc -E hello ?匚-o hello * i [root (alocalhost gcc ]# Is hello hel lo.c: hel lo.i 通过查看可以看到头文件包含部分代码 #include 经过预处理阶段之后,编译 器已将stdio.h 的内容贴了进来。 4、 -S 选项的使用 -S 选项的作用:只是编译不汇编,生成汇编代码 [root@localhost [root@localhost [root@localho5t hello world [rootglocalhost gcc]#

IAR -arm 入门教程

IAR 使用说明 关于文档(初版): 1.主要是为了给IAR的绝对新手作参考用 2.emot制件,由Zigbee & IAR 学习小组保持修订权 3.希望用IAR朋友能将它修订完善 4.任何人可无偿转载、传播本文档,无须申请许可,但请保留文档来源及标志 5.如无重大升级,请沿用主版本号 版本 版本号制作时间制定人/修改人说明 1.00 2008/7/27 emot 初版(仅供新手参考) 1.01 2010/8/19 Emot 增加 下载程序(第四章) 在线调试程序(第五章) 序: 其实IAR和keil区别也没有多大,不过很多人就是怕(当初我也怕)。怕什么呢,怕学会了,真的就是害怕学习的心理让新手觉得IAR是个不好用的或者说“还不会用的”一个工具吧。我也是一个刚毕业的小子,如果说得不妥,还请大家来点砖头,好让小组筑高起来。(Zigbee & IAR 学习小组地址是https://www.sodocs.net/doc/293943497.html,/673) 初版我将会说明以下3个问题,IAR的安装、第一个IAR工程的建立和工作编译。这是我写的第一个使用说明,不足的以后补充吧。 一、IAR软件安装图解 1.打开IAR软件安装包进入安装界面 打开软件开发包

软件安装界面 2.按照提示步骤执行,一直到授权页面,输入序列号,IAR中有两层序列号,所以要输入两 组序列号。 输入第一组序列号

3.选择安装路径(最好默认,不默认也不影响使用) 路径选择页面

修改路径4.选择全部安装(Full) 选择全部安装5.按提示知道安装完成。

安装完成页面 二、新建第一个IAR工程 用IAR首先要新建的是工作区,而不是工程。在工作区里再建立工程,一个工作区里似乎也不能建多个工程(我试过,但没成功,不知道IAR里提出workspace的概念是为什么?)要不打IAR的help来看,说清楚也是头痛的事,先知道有要在工作空间里建工程就对了。新建IAR工作空间,首先是菜单File里选择Open再选择Workspace,为方便说明再遇到菜 单我就直接说成File-Open-Workspace这样了。看了下面图上的红圈就知道是怎么回事了。 接着就会看到一片空白。这时就是新的“办公区”了。

国嵌视频教程下载

嵌入式Linux视频教程 相关搜索:简体中文, 学习方法, 视频教程, 普通话, 嵌入式 中文名: 嵌入式Linux视频教程 资源格式: 光盘镜像 学校: 成都国嵌嵌入式培训中心版本: 成都国嵌嵌入式培训中心的基于广州友善之发行日期: 2010年 地区: 大陆 对白语言: 普通话 文字语言: 简体中文 视频光盘目录结构 国嵌视频1.iso -学习方法与课程体系介绍(学前必看) -学习方法介绍.avi -国嵌嵌入式课程体系.pdf -嵌入式Linux学习方法.pdf -国嵌课程1-嵌入式入门体验班(上) -第1天(嵌入式系统概述) -国嵌体验入门班-1-1(嵌入式系统概述).avi -国嵌体验入门班-1-2(ARM概述).avi -国嵌体验入门班-1-3(嵌入式Linux概述).avi -国嵌体验入门班-1-4(2440开发板介绍).avi -国嵌体验入门班-1-5(软硬件环境搭建).avi -第2天(开发板快乐体验) -国嵌体验入门班-2-1(开发板系统安装).avi -国嵌体验入门班-2-1(开发板系统安装-Jlink方式).avi -国嵌体验入门班-2-1(开发板系统安装-并口方式).avi -国嵌体验入门班-2-2(裸机程序体验).avi -国嵌体验入门班-2-3(QT系统体验).avi -国嵌体验入门班-2-4(Android系统体验).avi 国嵌视频2.iso

-国嵌课程1-嵌入式入门体验班(下) -第3天(Linux系统体验) -国嵌体验入门班-3-1(Linux定制安装).avi -国嵌体验入门班-3-2(Linux命令).avi -国嵌体验入门班-3-3(VI使用).avi -国嵌体验入门班-3-4(Linux系统管理).avi -国嵌体验入门班-3-5(Shell编程).avi -国嵌体验入门班-3-6(Qcd功能演示).avi -国嵌体验入门班-3-7(必修实验).avi -国嵌课程2-嵌入式Linux应用开发班 -第1天(编程基础) -国嵌应用班-1-1(GCC程序编译).avi -国嵌应用班-1-2(GDB程序调试).avi -国嵌应用班-1-3(makefile工程管理).avi -国嵌应用班-1-4(必修实验).avi -第2天(文件时间编程) -国嵌应用班-2-1(系统调用方式访问文件).avi -国嵌应用班-2-2(库函数访问文件).avi -国嵌应用班-2-3(时间编程).avi -国嵌应用班-2-4(必修实验).avi -第3天(多进程程序设计) -国嵌应用班-3-1(进程控制原理).avi -国嵌应用班-3-2(进程控制程序设计).avi -国嵌应用班-3-3(必修实验).avi -第4天(进程间通讯) -国嵌应用班-4-1(进程间通讯概述).avi -国嵌应用班-4-2(管道通讯).avi -国嵌应用班-4-3(信号通讯).avi -国嵌应用班-4-4(共享内存通讯).avi -国嵌应用班-4-5(必修实验).avi -第5天(进程间通讯) -国嵌应用班-5-1(消息队列).avi

如何高效使用GDB断点

在gdb中,断点通常有三种形式 断点(BreakPoint): 在代码的指定位置中断,这个是我们用得最多的一种。设置断点的命令是break,它通常有如下方式: 可以通过info breakpoints [n]命令查看当前断点信息。此外,还有如下几个配套的常用命令: 观察点(WatchPoint): 在变量读、写或变化时中断,这类方式常用来定位bug。

捕捉点(CatchPoint): 捕捉点用来补捉程序运行时的一些事件。如:载入共享库(动态链接库)、C++的异常等。通常也是用来定位bug。 捕捉点的命令格式是:catch ,event可以是下面的内容 自动删除。 捕捉点信息的查看方式和代码断点的命令是一样的,这里就不多介绍了。 在特定线程中中断 你可以定义你的断点是否在所有的线程上,或是在某个特定的线程。GDB很容易帮你完成这一工作。

break thread break thread if ... linespec指定了断点设置在的源程序的行号。threadno指定了线程的ID,注意,这个ID是GDB分配的,你可以通过"info threads"命令来查看正在运行程序中的线程信息。如果你不指定thread 则表示你的断点设在所有线程上面。你还可以为某线程指定断点条件。如: (gdb) break frik.c:13 thread 28 if bartab > lim 当你的程序被GDB停住时,所有的运行线程都会被停住。这方便你你查看运行程序的总体情况。而在你恢复程序运行时,所有的线程也会被恢复运行。那怕是主进程在被单步调试时。 在特定条件下中断 条件断点的一种特殊场景是在断点命中指定次数后停下来。事实上每个断点都有一个 ignore count, 他是一个正整数。通常情况下它的值为0,所以看不出来它的存在。但是如果它是一个非0值, 那么它将在每次命中后都将 count 减 1,直到它为 0. ignore bnum count 恢复程序运行和单步调试 在gdb中,和调试步进相关的命令主要有如下几条: 参考资料

6、汇编学习从入门到精通(荐书)

汇编学习从入门到精通Step By Step 2007年12月15日星期六00:34 信息来源:https://www.sodocs.net/doc/293943497.html,/hkbyest/archive/2007/07/22/1702065.aspx Cracker,一个充满诱惑的词。别误会,我这里说的是软件破解,想做骇客的一边去,这年头没人说骇客,都是“黑客”了,嘎嘎~ 公元1999年的炎热夏季,我捧起我哥留在家的清华黄皮本《IBM-PC汇编语言程序设计》,苦读。一个星期后我那脆弱的小心灵如玻璃般碎裂了,为了弥补伤痛我哭爹求妈弄了8k大洋配了台当时算是主流的PC,要知道那是64M内存!8.4G硬盘啊!还有传说中的Celeon 300A CPU。不过很可惜的是在当时那32k小猫当道的时代,没有宽带网络,没有软件,没有资料,没有论坛,理所当然我对伟大的计算机科学体系的第一步探索就此夭折,此时陪伴我的是那些盗版光盘中的游戏,把CRACK_XXX文件从光盘复制到硬盘成了时常的工作,偶尔看到光盘中的nfo 文件,心里也闪过一丝对破解的憧憬。 上了大学后有网可用了,慢慢地接触到了一些黑客入侵的知识,想当黑客是每一个充满好奇的小青年的神圣愿望,整天看这看那,偷偷改了下别人的网页就欢喜得好像第一次偷到鸡的黄鼠狼。 大一开设的汇编教材就是那不知版了多少次的《IBM-PC汇编语言程序设计》,凭着之前的那星期苦读,考试混了个80分。可惜当时头脑发热,大学60分万岁思想无疑更为主流,现在想想真是可惜了宝贵的学习时间。 不知不觉快毕业了,这时手头上的《黑客防线》,《黑客X档案》积了一大摞,整天注来注去的也厌烦了,校园网上的肉鸡一打一打更不知道拿来干什么。这时兴趣自然转向了crack,看着杂志上天书般的汇编代码,望望手头还算崭新的汇编课本,叹了口气,重新学那已经忘光了的汇编语言吧。咬牙再咬牙,看完寻址方式那章后我还是认输,不认不行啊,头快裂了,第三次努力终告失败。虽然此时也可以爆破一些简单的软件,虽然也知道搞破解不需要很多的汇编知识,但我还是固执地希望能学好这门基础中的基础课程。 毕业了,进入社会了,找工作,上班,换工作成了主流旋律,每天精疲力尽的哪有时间呢?在最初的中国移动到考公务员再到深圳再到家里希望的金融机构,一系列的曲折失败等待耗光了我的热情,我失业了,赋闲在家无所事事,唯一陪伴我的是那些杂志,课本,以及过时的第二台电脑。我不想工作,我对找工作有一种恐惧,我靠酒精麻醉自己,颓废一段日子后也觉得生活太过无聊了,努力看书考了个CCNA想出去,结果还是被现实的就业环境所打败。三年时间,一无所获。 再之后来到女朋友处陪伴她度过刚毕业踏入社会工作的适应时期,这段时间随便找了个电脑技术工作,每月赚那么个几百块做生活费。不过这半年让我收获比较大的就是时间充裕,接触到了不少新东西,我下定决心要把汇编学好,这时我在网上看到了别人推荐的王爽《汇编语言》,没抱什么希望在当当网购了人生中的第一次物,19块6毛,我记得很清楚,呵呵。 废话终于完了,感谢各位能看到这里,下面进入正题吧。

Windows X86-64位汇编语言入门

Windows X86-64位汇编语言入门 Windows X64汇编入门(1) 最近断断续续接触了些64位汇编的知识,这里小结一下,一是阶段学习的回顾,二是希望对64位汇编新手有所帮助。我也是刚接触这方面知识,文中肯定有错误之处,大家多指正。 文章的标题包含了本文的四方面主要内容: (1)Windows:本文是在windows环境下的汇编程序设计,调试环境为Windows Vista 64位版,调用的均为windows API。 (2)X64:本文讨论的是x64汇编,这里的x64表示AMD64和Intel的EM64T,而不包括IA64。至于三者间的区别,可自行搜索。 (3)汇编:顾名思义,本文讨论的编程语言是汇编,其它高级语言的64位编程均不属于讨论范畴。 (4)入门:既是入门,便不会很全。其一,文中有很多知识仅仅点到为止,更深入的学习留待日后努力。其二,便于类似我这样刚接触x64汇编的新手入门。 本文所有代码的调试环境:Windows Vista x64,Intel Core 2 Duo。 1. 建立开发环境 1.1 编译器的选择 对应于不同的x64汇编工具,开发环境也有所不同。最普遍的要算微软的MASM,在x64环境中,相应的编译器已经更名为ml64.exe,随Visual Studio 2005一起发布。因此,如果你是微软的忠实fans,直接安装VS2005既可。运行时,只需打开相应的64位命令行窗口(图1),便可以用ml64进行编译了。

第二个推荐的编译器是GoASM,共包含三个文件:GoASM编译器、GoLINK链接器和GoRC 资源编译器,且自带了Include目录。它的最大好外是小,不用为了学习64位汇编安装几个G 的VS。因此,本文的代码就在GoASM下编译。 第三个Yasm,因为不熟,所以不再赘述,感兴趣的朋友自行测试吧。 不同的编译器,语法会有一定差别,这在下面再说。 1.2 IDE的选择 搜遍了Internet也没有找到支持asm64的IDE,甚至连个Editor都没有。因此,最简单的方法是自行修改EditPlus的masm语法文件,这也是我采用的方法,至少可以得到语法高亮。当然,如果你懒得动手,那就用notepad吧。 没有IDE,每次编译时都要手动输入不少参数和选项,做个批处理就行了。 1.3 硬件与操作系统 硬件要求就是64位的CPU。操作系统也必须是64位的,如果在64位的CPU上安装了

GDB调试精粹及使用实例

GDB调试精粹及使用实例 一:列文件清单 1. List (gdb) list line1,line2 二:执行程序 要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。 如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。 利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。 (gdb)set args –b –x (gdb) show args backtrace命令为堆栈提供向后跟踪功能。 Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 三:显示数据 利用print 命令可以检查各个变量的值。 (gdb) print p (p为变量名) whatis 命令可以显示某个变量的类型 (gdb) whatis p type = int * print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容: l 对程序中函数的调用 (gdb) print find_entry(1,0) l 数据结构和其他复杂对象 (gdb) print *table_start $8={e=reference=’\000’,location=0x0,next=0x0} l 值的历史成分 (gdb)print $1 ($1为历史记录变量,在以后可以直接引用 $1 的值) l 人为数组 人为数组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们查看内存中在变量h后面的10个整数,一个动态数组的语法如下所示: base@length 因此,要想显示在h后面的10个元素,可以使用h@10: (gdb)print h@10 $13=(-1,345,23,-234,0,0,0,98,345,10)

linuxvimgccgdb开发cc程序环境搭建

linux+vim+gcc+gdb开发C/C++程序环境搭建 我用的是ubuntu操作系统。打开终端 1.sudo apt-get install vim(vim-full 这个软件自9.10版本被废弃了,不论怎么添加软件源都找不到的,所以直接安装vim就可以了,,也可以安装gvim,,在新立得软件里面搜索vim 就可以找到了) 2.sudo apt-get install build-essential // build-essential是c语言的开发包,包含了gcc make gdb和libc函数库很多工具。 或者sudo apt-get install gcc + sudo apt-get install gdb 网上有很多版本说要编译安装,这个可能挺复杂的,而且花的时间也不少(没试过阿),,不想在命令行中安装的化,可以下载rpm包直接点击安装, 3.gcc只是一个编译器,vim是编辑器(也可以用gedit编辑源代码),gdb是调试器,, 可以新建一个test.c的helloworld文件测试以下 4.一般c程序就用gcc编译,c++程序就用g++编译

[介绍] ----------------------------------------- 常见用法: GCC 选项 GCC 有超过100个的编译选项可用。这些选项中的许多你可能永远都不会用到,但一些主要的选项将会频繁用到。很多的GCC 选项包括一个以上的字符。因此你必须为每个选项指定各自的连字符,并且就象大多数Linux 命令一样你不能在一个单独的连字符后跟一组选项。例如,下面的两个命令是不同的: gcc -p -g test.c gcc -pg test.c 第一条命令告诉GCC 编译test.c 时为prof 命令建立剖析(profile)信息并且把调试信息加入到可执行的文件里。第二条命令只告诉GCC 为gprof 命令建立剖析信息。 当你不用任何选项编译一个程序时,GCC 将会建立(假定编译成功)一个名为 a.out 的可执行文件。例如,下面的命令将在当前目录下产生一个叫 a.out 的文件: gcc test.c 你能用-o 编译选项来为将产生的可执行文件指定一个文件名来代替 a.out。例如,将一个叫count.c 的 C 程序编译为名叫count 的可执行文件,你将输入下面的命令: gcc -o count count.c 注意: 当你使用-o 选项时, -o 后面必须跟一个文件名。 -c 只编译并生成目标文件。 -------------------------------------------------------------------------------- gcc and g++分别是gnu的c & c++编译器gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2.将预处理后的文件转换成汇编语言,生成文件.s[编译器egcs] 3.有汇编变为目标代码(机器代码)生成.o的文件[汇编器as] 4.连接目标代码,生成可执行程序[链接器ld] [参数详解]

汇编语言入门

汇编语言入门教程 对初学者而言,汇编的许多命令太复杂,往往学习很长时间也写不出一个漂漂亮亮的程序,以致妨碍了我们学习汇编的兴趣,不少人就此放弃。所以我个人看法学汇编,不一定要写程序,写程序确实不是汇编的强项,大家不妨玩玩DEBUG,有时CRACK出一个小软件比完成一个程序更有成就感(就像学电脑先玩游戏一样)。某些高深的指令事实上只对有经验的汇编程序员有用,对我们而言,太过高深了。为了使学习汇编语言有个好的开始,你必须要先排除那些华丽复杂的命令,将注意力集中在最重要的几个指令上(CMP LOOP MOV JNZ……)。但是想在啰里吧嗦的教科书中完成上述目标,谈何容易,所以本人整理了这篇超浓缩(用WINZIP、WINRAR…依次压迫,嘿嘿!)教程。大言不惭的说,看通本文,你完全可以“不经意”间在前辈或是后生卖弄一下DEBUG,很有成就感的,试试看!那么――这个接下来呢?――Here we go!(阅读时看不懂不要紧,下文必有分解) 因为汇编是通过CPU和内存跟硬件对话的,所以我们不得不先了解一下CPU和内存:(关于数的进制问题在此不提) CPU是可以执行电脑所有算术╱逻辑运算与基本I/O 控制功能的一块芯片。一种汇编语言只能用于特定的CPU。也就是说,不同的CPU其汇编语言的指令语法亦不相同。个人电脑由1981年推出至今,其CPU发展过程为:8086→80286→80386→80486→PENTIUM →……,还有AMD、CYRIX等旁支。后面兼容前面CPU的功能,只不过多了些指令(如多能奔腾的MMX指令集)、增大了寄存器(如386的32位EAX)、增多了寄存器(如486的FS)。为确保汇编程序可以适用于各种机型,所以推荐使用8086汇编语言,其兼容性最佳。本文所提均为8086汇编语言。寄存器(Register)是CPU内部的元件,所以在寄存器之间的数据传送非常快。用途:1.可将寄存器内的数据执行算术及逻辑运算。2.存于寄存器内的地址可用来指向内存的某个位置,即寻址。3.可以用来读写数据到电脑的周边设备。8086 有8个8位数据寄存器,这些8位寄存器可分别组成16位寄存器:AH&AL=AX:累加寄存器,常用于运算;BH&BL=BX:基址寄存器,常用于地址索引;CH&CL=CX:计数寄存器,常用于计数;DH&DL=DX:数据寄存器,常用于数据传递。为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:CS(Code Segment):代码段寄存器;DS(Data Segment):数据段寄存器;SS(Stack Segment):堆栈段寄存器;ES(Extra Segment):附加段寄存器。当一个程序要执行时,就要决定程序代码、数据和堆栈各要用到内存的哪些位置,通过设定段寄存器CS,DS,SS 来指向这些起始位置。通常是将DS固定,而根据需要修改CS。所以,程序可以在可寻址空间小于64K的情况下被写成任意大小。所以,程序和其数据组合起来的大小,限制在DS 所指的64K内,这就是COM文件不得大于64K的原因。8086以内存做为战场,用寄存器做为军事基地,以加速工作。除了前面所提的寄存器外,还有一些特殊功能的寄存器:IP(Intruction Pointer):指令指针寄存器,与CS配合使用,可跟踪程序的执行过程;SP(Stack Pointer):堆栈指针,与SS配合使用,可指向目前的堆栈位置。BP(Base Pointer):基址指针寄存器,可用作SS 的一个相对基址位置;SI(Source Index):源变址寄存器可用来存放相对于DS段之源变址指针;DI(Destination Index):目的变址寄存器,可用来存放相对于ES 段之目的变址指针。还有一个标志寄存器FR(Flag Register),有九个有意义的标志,将在下文用到时详细说明。 内存是电脑运作中的关键部分,也是电脑在工作中储存信息的地方。内存组织有许多可存放

汇编语言-王爽-完美高清版视频教程

汇编语言》-王爽-完美高清版-零基础汇编语言入门书籍PDF格式 同时按ctrl+要下载的地址既可下载对应的视频 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f61cb107c8 001第一章- 基础知识01 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6806f45b8 002第一章- 基础知识02 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6ec42d4d3 003第一章- 基础知识03 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6deb05ec4 004第一章-基础知识04 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6e51f6838 005第一章- 基础知识05 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f66edaf8d3 006第二章- 寄存器(CPU工作原理)01 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6d07e07b9 007第二章- 寄存器(CPU工作原理)02 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6d7f585a8 008第二章- 寄存器(CPU工作原理)03 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f639d8b3cf 009第二章- 寄存器(CPU工作原理)04 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6dcadbde6 010第二章- 寄存器(CPU工作原理)05 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6ea3f01c1 011第二章- 寄存器(CPU工作原理)06 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f65b96a06f 012第二章- 寄存器(CPU工作原理)07 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f682da085a 013第三章- 寄存器(内存访问)01 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6486e698 014第三章- 寄存器(内存访问)02 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6b7491d9f 015第三章- 寄存器(内存访问)03 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f622b7f9a7 016第三章- 寄存器(内存访问)04 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f64e2424b9 017第三章- 寄存器(内存访问)05 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6e5132d4d 018第三章- 寄存器(内存访问)06 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f655c10e86 019第三章- 寄存器(内存访问)07 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6b22e64e6 020第四章- 第一个程序01 下载地址:https://www.sodocs.net/doc/293943497.html,/file/f6812126a4

GDB调试及实例

GDB调试及实例 一:列文件清单 1.List (gdb) list line1,line2 二:执行程序 要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。 如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。 利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。 (gdb)set args –b –x (gdb) show args backtrace命令为堆栈提供向后跟踪功能。 Backtrace 命令产生一张列表,包含着从最近的过程开始的所以有效过程和调用这些过程的参数。 三:显示数据 利用print 命令可以检查各个变量的值。 (gdb) print p (p为变量名) whatis 命令可以显示某个变量的类型 (gdb) whatis p type = int * print 是gdb的一个功能很强的命令,利用它可以显示被调试的语言中任何有效的表达式。表达式除了包含你程序中的变量外,还可以包含以下内容: l 对程序中函数的调用 (gdb) print find_entry(1,0) l 数据结构和其他复杂对象 (gdb) print *table_start $8={e=reference=’\000’,location=0x0,next=0x0} l 值的历史成分 (gdb)print $1 ($1为历史记录变量,在以后可以直接引用$1 的值) l 人为数组 人为数组提供了一种去显示存储器块(数组节或动态分配的存储区)内容的方法。早期的调试程序没有很好的方法将任意的指针换成一个数组。就像对待参数一样,让我们查看内存中在变量h后面的10个整数,一个动态数组的语法如下所示: base@length 因此,要想显示在h后面的10个元素,可以使用h@10: (gdb)print h@10 $13=(-1,345,23,-234,0,0,0,98,345,10)

相关主题