c语言逆向基础

原创 2015年11月21日 12:00:45

0x00 全局变量

  • 整数(00x12345678)在内存中的表示方式:
    大端机:逻辑上低字节放在内存低地址(高高低低原则),78 56 34 12.Intel x86
    小端机:逻辑上高字节放在内存低地址,12 34 56 78.PowerPC
  • 全局变量的线性地址在编译时已经写定了,故每个进程中同一个全局变量的线性地址是相同的。
    这里写图片描述
  • 在CPU的保护模式下,对于同一个程序的每个进程都有自己独立的线性地址空间(0—4GB),这种机制叫虚拟系统
    这里写图片描述
    注:寄存处—>进程 仓库—>物理存储系统
    寄存处编号—>线性地址 仓库编号—>物理内存地址
  • 程序访问内存用的是线性地址(mov指令中的地址就是线性地址,用户态程序无法直接访问物理内存), 虚拟管理系统将该地址转换成对应物理地址进行访问。
  • 同一程序两个进程的线性地址相同,但对应物理内存是不同的。

0x01 指针

  • 作用:地址、类型
    指针类型信息(读写字节大小)不放在指针变量中,而是放在了与该地址相关的赋值语句中,即mov指令中dword指明指针类型。
int *pi;    int gi;  pi = &gi;
00C6139E  mov   dword ptr ds:[00C67138h],0C6713Ch  ;pi存着gi地址
*pi = 12;
00C613A8  mov   eax,dword ptr ds:[00C67138h];将pi中存的gi地址给eax
00C613AD  mov   dword ptr [eax],0Ch  ;将0Ch赋给gi
  • 注:&pi = 00C67138h 、 &gi = 0C6713Ch

  • 指针强制转换
    强制转换并没有实际的指令,转换的影响不是发生在转换的时候,而是用转换后的身份去访问内存时体现在指令中的。
    eg:int i; int *pi; short *ps; char *pc;
    这里写图片描述
    运行17行后:
    这里写图片描述
    运行18行后:
    这里写图片描述
    运行19行后:
    这里写图片描述

0x02 函数调用和局部变量

1) 函数调用

int Add(int x,int y)
{
    int sum;
    sum = x+y;
    return sum;
}
void main()
{
    int z;
    z = Add(1,2);
    printf("%d\n",z);
}
  • 反汇编代码
    这里写图片描述

  • call指令由相对定位进行跳转:跳转到子函数的 = call指令下一条指令起始地址 + 偏移量
    call指令地址 + call指令长度(5) + 偏移量

  • 偏移量:fffff99b为负数补码,原整数 = -665h。数值位取反加1
    故00d511c2h = 00d51822h +5h -665h
  • 每次压栈,32位机用4字节存储栈值。X86中,push指令使ESP的值减4
  • call指令功能:a) push 返回地址 b) jump 函数入口地址

2) 参数传递

  • 参数地址 = EBP + 偏移量
  • 局部变量地址 = EBP – 偏移量
    Visual C++6.0中第一个局部变量地址为EBP-4,VS2005版本开始则为EBP – 8,这是因为吸取了Stack Guard的溢出攻击防护机制
    这里写图片描述

3) 函数调用返回

  • ret指令功能:相当于pop eip,将栈顶保存的返回地址弹入EIP

4) 函数返回值

  • 一般将返回值存在EAX中,函数在执行ret指令前mov eax , 返回值
    这里写图片描述
  • 子函数返回值较小时,将其先保存到母函数栈帧局部变量区临时内存中,然后再赋给母函数局部变量
  • 子函数返回值较大时,先分配一段内存用于保存返回值,并将该内存地址传给子函数,将返回值存入该内存,母函数通过该地址获取返回值

5) 平衡栈

  • 调用方清栈,call返回后执行add esp,x
  • 被调方清栈,执行ret x
    前者用空间代价换取了变参功能

0x03 函数指针

  • 函数指针成功赋值的前提:参数表、调用惯例、返回类型一致
  • 函数指针的作用:让函数指针指向不同函数,实现同样的调用代码调用不同的函数。相当于面向对象中虚函数的作用
int(*pfunc)(int,int);
int _cdecl add(int x,int y)
{
    int sum;
    sum = x + Y;
    return sum;
}
void main(0
{
    pfunc = add;
    pfunc = &add;
    pfunc(1,2);
    add(1,2);
}
  • 反汇编代码
    这里写图片描述
  • 函数指针不能强制转换

0x04 数组

  • 用首部地址+偏移量的形式访问
void main()
{
    int array[5];
    int i = 0;
    for(i;i<5;i++)
    {
        array[i] = i;
    }
    for(i = 0;i <7;i++)
    {
        printf("%d ",array[i]);
    }
}
  • 反汇编代码
    这里写图片描述
  • 变量在栈中的分布
    这里写图片描述
  • 无法从反编译结果看出某块内存是结构体还是相邻的局部变量

0x05 对齐

  • 对齐:基本数据(如单字节、双字节、四字节整数)存放处的地址必须能被自己数据类型的大小整除。若不满足要求,不同体系结构的CPU反应不同。有的直接结束进程的执行,有的访问速度变慢(x86)。
  • 结构体的对齐
    首先选定一个盒子,依次将字段往盒子中放,盒子放不下后,用下一个盒子存放
    限制条件:
    a)盒子长度 = min{max{sizeof(成员变量)},对齐长度}
    b)字段放入位置:离盒子头部偏移 = n *sizeof(成员变量) n = 0,1,2,….
    c)适用VS编译器
  • eg:
    当对齐长度为4时,sizeof(Person) = 12
    这里写图片描述
struct Person   
{
    char c1;
    short s;            
    char c2;
    int i;
};
  • 网络编程中,协议头部一般用结构体表示,在自己手动构造数据包强制转换并赋给头部结构体时应注意对齐问题
struct ip_hdr
{
    char version;
    char ihl;
    unsigned char tos;
    unsigned short tot_len;
    unsigned short id;
    unsigned short frag_off;
    unsigned char ttl:
    unsigned char protocol;
    unsigned short check;
    unsigned int saddr;
    unsigned int daddr;
}

发送方:

char buf[128];
int * pdataLen;
buf[0] = 1;         //设定标志类型
pdataLen = (int *)&buf[1];
*pdataLen = htonl(12);      //设定数据长度
//填充数据部分12字节
buf[5] = 1;
buf[6] = 2;
...
buf[16] = 12;
...
//将buf开始的17个字节发送出去,包括头部5字节,数据12字节
send(sockethnd,buf,5 + 12,0);

接收方:

struct hdr* phdr;
char buf[128];
int dataLen;
recv(sockethnd,buf,5,0);
phdr = (struct hdr*)buf;
printf("hdr flag is %\n",dataLen);

第五行指针赋值过程会因为结构体的对齐出现问题。
解决办法:
a) 调整结构体成员变量的顺序达到对齐
b) 填充reserved字段以达到对齐

版权声明:本文为博主原创文章,未经博主允许不得转载。

c&c++反汇编与逆向分析学习笔记(1)--调试工具OllyDBG

我学习用的数据是钱松林和赵海合著的《C反汇编与逆向分析技术揭秘》,这本书绝对可以帮助程序员提高自己,修炼自己的内功。 在软件的开发过程中,程序员会使用一些调试工具,以便高效地找出软件中存在的错误...
  • kyt511
  • kyt511
  • 2015年04月04日 17:14
  • 3006

逆向还原C语言代码 练习1

找了个C语言100列 用来练习OD还原C语言代码 至于C+的 以后也会写 今天的课件下载 链接: http://pan.baidu.com/s/1nvApltJ 密码: sgur 我们先来看第...
  • MrXiao95
  • MrXiao95
  • 2016年11月30日 10:01
  • 693

c语言逆向基础

1. 全局变量 整数(00x12345678)在内存中的表示方式: 大端机:逻辑上低字节放在内存低地址(高高低低原则),78 56 34 12.Intel x86 小端机:逻辑上高字节放在内存低...
  • swjtu100
  • swjtu100
  • 2015年11月21日 12:00
  • 513

滴水逆向 文件操作(pe修改)C语言源代码

  • 2017年06月20日 17:09
  • 107KB
  • 下载

Android逆向基础笔记—初识逆向

(本笔记来源于吾爱以及吾爱坛友,加上本人自己的整理) 一.初识 APK、Dalvik字节码以及Smali 1. apk是什么? apk实质上是一个zip压缩包,将apk后缀修改为zip,解压之后可以...
  • qq_24349189
  • qq_24349189
  • 2016年08月24日 14:47
  • 2226

Android逆向-Android基础逆向(1)

0x00 前言 学习的目的 工具使用 学习相关基础 学习内容 0x01 Android helloworld 第一步 第二步 第三步 第四步 第五步 第六步 第七步 0x02 Android APK分...
  • qq_36869808
  • qq_36869808
  • 2018年01月24日 19:23
  • 858

c/c++逆向(一)

一个基本的c console程序 : int Sum1(int nNum1, int nNum2) { int nRet = 0; nRet = nNum1 + nNum2; return nR...
  • qq2765757213
  • qq2765757213
  • 2015年06月09日 20:37
  • 78

培训基础教程滴水逆向-C语言笔记

  • 2016年06月01日 23:13
  • 390KB
  • 下载

c语言用尾递归实现单向链表的逆向排列

c++的stl很好用,c语言的简单链表最近几年几乎不用了。最近一次笔试,遇到了这题,就十分捉急。当时想到似乎得用递归。现在算是完成了。 以下以简单的单向链表(链表头结点跟普通结点一致)为例。 #in...
  • u010607621
  • u010607621
  • 2017年02月09日 10:32
  • 403

递归逆向输出字符串

输入一个字符串,编写递归函数将字符串按相反的顺序输出。 #include #include #include #include int reverse(char *str, int sta...
  • iamzxf
  • iamzxf
  • 2013年12月17日 08:35
  • 978
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:c语言逆向基础
举报原因:
原因补充:

(最多只允许输入30个字)