学习笔记(逆向汇编)Day6-Day10

Day 6  《修改EIP》

(一)调试

1.调试的基础概念:
断点,就是让CPU一条一条的执行指令,这样方便我们观察寄存器的变化;
EPI:就是我们下次要调到的地址;
注意:mov无法修改EIP的值;

2.JMP指令:修改EIP的值
格式:MOV EIP,寄存器/立即数

#include<stdio.h>

int main()
{
   __asm {
      mov eax,0xBBBBBBBB
      add eax,1
      jmp eax
   }
   //因为有保护模式,在vs上是不允许这么做的
   return 0;
}

JMP:多数人理解是跳转,其实是错误的,它没有跳转,只是对EIP进行了修改。它只影响EIP;
MOV EIP,寄存器/立即数 => JMP 寄存器/立即数

3.CALL指令:将当前EIP入栈,并修改EIP的值
格式:CALL 地址A/寄存器

不同的CPU可能有不同的规定。下面只说常见的简单CPU的指令。
常见的CPU的CALL指令(“调用”指令)的功能,就是以下两点:
  (1)将下一条指令的所在地址(即当时程序计数器PC的内容)入栈
  (2)并将子程序的起始地址送入PC(于是CPU的下一条指令就会转去执行子程序)。
而子程序结尾处通常都要编写一条RET指令(“返回”指令)
RET指令的功能就是一条:从栈中取出一条数据送入PC。

4.练习:
1. CALL执行时堆栈有什么变化?EIP有变化吗?

堆栈会存入一个地址,并且esp会-4,eip会改变数值。


  1. RET执行堆栈有什么变化?EIP有变化吗?

RET执行,堆栈会pop出,esp+4,eip的值改变。

2017/5/15 20:26:03

Day 7  《堆栈图》

(一)简单堆栈图

源程序:

#include<stdio.h>

void add(int x, int y)
{
   x = x + y;
}
int main()
{
   add(1, 2);
   return 0;
}

汇编代码:

执行堆栈图:

说明:

push ebp这里就是保留栈底

mov ebp,esp
sub esp,4 保留栈底的作用就是提升栈顶。我们程序执行的时候需要用到内存

push ebx
push esi
push edi 保存现场,把有可能用的寄存器的值放到内存中去

lea edi,[ebp-0xC0]
mov ecx,30h
mov eax,cccccccc 这个作用是我们分配的内存不能放置垃圾数据


2017/5/16 20:47:36

Day 8  《函数》

(一)函数

1.C的函数:
计算机的函数,是一个固定的一个程序段,或称其为一个子程序,它可以实现固定运算功能的同时,还带有一个入口和一个出口;
所谓入口,就是函数所带的各个参数,我们可以通过这个入口,把函数的参数值代入子程序,供计算机处理;
所谓出口,就是指函数的计算结果,也称为返回值,再计算机求得之后,由此口带回给调用它的程序。

2.汇编中的函数:

push        ebp               //提升堆栈,为函数执行提供空间
mov         ebp,esp  
sub         esp,0C0h 

push        ebx               //保留现场:函数在执行的时候会用到一些寄存器,但这些寄存器中的值很可能会程序用到,所以要先存储到内存中
push        esi  
push        edi

lea         edi,[ebp-0C0h]    //向分配的空间填充数据
mov         ecx,30h  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]   

mov         eax,dword ptr [x] //该函数的功能;在这里是x=x+y;
add         eax,dword ptr [y]  
mov         dword ptr [x],eax 

pop         edi               //恢复现场:将之前保留的寄存器的值恢复
pop         esi 
pop         ebx

mov         esp,ebp           //降低堆栈

pop         ebp               //恢复栈底

ret                           //函数执行完毕,返回到调用处

注意:Debug 和 Release 是有区别的

3.函数的入口:

push        2                 //函数的参数
push        1  
call        add (0134128Ah)   //调用函数  

call 就是调用一个函数,逆向中经常提到的找Call

4.windows堆栈的特点:
1. 先进后出
2. 向低地址扩展

5.堆栈平衡:
  windows中的堆栈,是一块普通的内存,主要用来存储一些临时的数据和参数等。当函数再执行的时候,会用到堆栈,把一些数据存到里面,但用完的时候一定要把栈中的数据弹出清除,否则就会乱,这个就是堆栈平衡;

  判断函数的参数,push的个数不是100%准确的。具体的要往里面看。

(二)绘制堆栈图,在函数中又调用一个函数:

源C代码:

#include<stdio.h>
void Fun_1(int a, int b)
{

}
void Fun_2(int a, int b, int c)
{
   Fun_1(a, b);
}

int main()
{
   Fun_2(0x10, 0x20,0x30);
   return 0;
}

汇编代码:

_main:
    push        ebp  
    mov         ebp,esp  
    sub         esp,0C0h  
    push        ebx  
    push        esi  
    push        edi  
    lea         edi,[ebp-0C0h]  
    mov         ecx,30h  
    mov         eax,0CCCCCCCCh  
    rep stos    dword ptr es:[edi]  
    push        30h               //此处开始传入参数调用函数
    push        20h  
    push        10h  
    call        _Fun_2 (0D110Eh)  //此处的CS:[EIP] 000D1744    
    add         esp,0Ch           //此处的CS:[EIP] 000D1749    将刚刚入栈的 30h、20h、10h数据出栈
    xor         eax,eax  
    pop         edi  
    pop         esi  
    pop         ebx  
    add         esp,0C0h  
    cmp         ebp,esp  
    call        __RTC_CheckEsp (0D1113h)  
    mov         esp,ebp  
    pop         ebp  
    ret  

(0D110Eh)jmp         Fun_2 (0D16C0h)

(0D16C0h)_Fun_2:
    push        ebp  
    mov         ebp,esp  
    sub         esp,0C0h  
    push        ebx  
    push        esi  
    push        edi  
    lea         edi,[ebp-0C0h]  
    mov         ecx,30h  
    mov         eax,0CCCCCCCCh  
    rep stos    dword ptr es:[edi]  
    mov         eax,dword ptr [b]  
    push        eax  
    mov         ecx,dword ptr [a]  
    push        ecx  
    call        _Fun_1 (0D1109h)  
    add         esp,8  
    pop         edi  
    pop         esi  
    pop         ebx  
    add         esp,0C0h  
    cmp         ebp,esp  
    call        __RTC_CheckEsp (0D1113h)  
    mov         esp,ebp  
    pop         ebp  
    ret  

堆栈图:


2017/5/17 20:21:03

Day 9  《绘制堆栈图2》

1.C程序代码:

#include<stdio.h>

int add2(int i, int j)
{
   return i + j;
}
int add3(int i, int j,int k)
{
   return i + j + k;
}

int main()
{
   int a = add2(1, 2);
   int b = add3(3, 4, 5);
   return 0;
}  

2.汇编代码:

main
push        ebp  
mov         ebp,esp  
sub         esp,0D8h  
push        ebx  
push        esi  
push        edi  
lea         edi,[ebp-0D8h]  
mov         ecx,36h  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
push        2                       //参数入栈 2 1
push        1  
call        add2 (0811343h)         //调用函数add2
add         esp,8                   //堆栈平衡
mov         dword ptr [a],eax  
push        5                       //参数入栈 5 4 3
push        4  
push        3  
call        add3 (0811348h)         //调用函数add3
add         esp,0Ch                 //堆栈平衡
mov         dword ptr [b],eax  
xor         eax,eax  
pop         edi  
pop         esi  
pop         ebx  
add         esp,0D8h  
cmp         ebp,esp  
call        __RTC_CheckEsp (0811109h)  
mov         esp,ebp  
pop         ebp  
ret  

add2
push        ebp                     //开栈
mov         ebp,esp  
sub         esp,0C0h  
push        ebx                     //保存现场
push        esi  
push        edi  
lea         edi,[ebp-0C0h]          //给缓冲区填充数据
mov         ecx,30h  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi] 
mov         eax,dword ptr [i]       //函数操作
add         eax,dword ptr [j]  
pop         edi                     //恢复现场
pop         esi  
pop         ebx  
mov         esp,ebp                 //降低堆栈
pop         ebp                     //恢复调用前基地址寄存器的值
ret                                 //函数返回

add3
push        ebp                     //开栈
mov         ebp,esp  
sub         esp,0C0h  
push        ebx                     //保存现场  
push        esi  
push        edi  
lea         edi,[ebp-0C0h]          //给缓冲区填充数据  
mov         ecx,30h  
mov         eax,0CCCCCCCCh  
rep stos    dword ptr es:[edi]  
mov         eax,dword ptr [i]       //函数操作  
add         eax,dword ptr [j]  
add         eax,dword ptr [k]  
pop         edi                     //恢复现场  
pop         esi  
pop         ebx  
mov         esp,ebp                 //降低堆栈  
pop         ebp                     //恢复调用前基地址寄存器的值  
ret                                 //函数返回  

3.堆栈图:
此时调用add2函数:
堆栈图
调用add3函数同上操作;


2017/5/18 10:47:22

Day 10  《裸函数及其执行》

(一)裸函数

1.什么是裸函数:
在试用编译器的时候,其编译器和链接器会为我们生成许多东西。如下图:
1. 普通函数调用:

2. 裸函数调用:

3. _declspec(naked)修饰可以生成一个“裸”函数, 使用后C编译器将生成不含函数框架的纯汇编代码,裸函数中什么都没有,所以也不能使用局部变量,只能全部用内嵌汇编实现。就是告诉编译器,在编译的时候,不要优化代码,通俗的说就是没代码,完全要自己写; 
 
4. 使用__declspec(naked)关键字定义函数:
 a.使用 naked 关键字必须自己构建 EBP 指针 (如果用到了的话);
 b.必须自己使用 RET 或 RET n 指令返回 (除非你不返回);

_delcspec(naked)用在驱动编写,C语言内嵌汇编完成一些特定功能。

2.练习:
用__declspec(naked)裸函数实现下面的功能:
int plus(int x,int y,int z)
{
int a = 2;
int b = 3;
int c = 4;
return x+y+z+a+b+c;
}
练习目的:
(1)熟悉堆栈结构
(2)参数、局部变量的位置
(3)返回值存储的位置

#include<stdio.h>

void __declspec(naked) plus(int x,int y,int z)
{
   __asm {
      //保留调用前的栈底
      push ebp
      //提升堆栈
      mov ebp,esp
      sub esp,0x40
      //保留现场
      push ebx
      push esi
      push edi
      //填充缓冲区
      mov eax,0xcccccccc
      mov ecx,0x10              
      lea edi,dword ptr ds:[ebp - 0x40]
      rep stosd
      //函数的核心功能
      mov eax,dword ptr ds:[ebp+0x8]
      add eax,dword ptr ds:[ebp+0xC]
      add eax,dword ptr ds:[ebp+0x10]
      //恢复现场
      pop edi
      pop esi
      pop ebx
      //降低堆栈
      mov esp,ebp
      pop ebp

      ret
   }
}

int main()
{
   plus(1,2,3);
   return 0;
}
(二)调用约定

1.常见的几种约定:


2.函数入口:
调用方式是自下向上调用的,真正的入口是mainCRTStartup函数;

mainCRTStartup()函数帮我们做了很多的初始化工作;
Main函数实际是传递了三个参数,在OD中,使用控制台程序找到程序入口,就先找到那几个函数然后查看谁push了3次后面调用的就是main。

(三)逆向你的基础C语言

1.数据类型
学习数据类型的三个要素:
 1. 存储数据的宽度;
 2. 存储数据的格式;
 3. 作用范围(作用域);

2.整数类型:char short int long

计算机底层不关心符号,计算机有无符号,是使用者定义的。计算机会根据指定的有无符号来生成对应的汇编语句;

3.浮点数:

如果是负数,只需要在符号位处0改为1即可,例如上图的16.44,如果变成-16.44,其在内存中的存储(16进制表示)为:1F 85 83 C1

再举个例子:


2017/5/19 21:20:13

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值