一、全局变量与局部变量
程序在运行时,会把内存分为如下区域
代码区:函数的一些功能,可读可执行的,cpu可以把数据读出来,我们写的程序比如if,else,while都在这里面,我们平时的push ebp啥的就是代码区
堆栈:参数,局部变量,临时数据(比如两个数运算的中间结果)。函数不执行的时候数据是不会放到堆栈里的,调用函数后才会把参数放到内存,也就是放到堆栈里,函数执行完毕后,这些曾经放的数就变为垃圾了,比如push ebp的代码执行后就把ebp的值存到堆栈了
堆:比如int arr[10],这个数组,要存很多个整数,不确定存多少个,要动态的往里面存东西,就要用到堆。动态申请的,大小可变的,可读,可写的
全局变量区:比如int x,全局变量区,可读、可写的
常量区:只读的,不可改的,只能把数据读出来(比如内存不让写入啥的)
局部变量
#include “stdafx.h”
void Plus()
{
int x =10;
printf("%d",x);
}
void Plus2()
{
printf("%d",x);
}
int main(int argc, char*argv[])
{
plus();
}
这个x就是只能大括号里面可以用的,称为局部变量,在plus2中不能打印出来这个就是在正向代码中的局部变量
局部变量特点:
局部变量在程序在程序编译完成后没有分配固定的地址
在所属方法没有调用时,局部变量不会分配内存地址,只有堆栈中分配内存
局部变量方法执行完成后,局部变量的内存将变成垃圾
局部变量只能在方法内部使用,函数A无法使用B的函数变量
函数变量的反汇编识别:[ebp-4],[ebp-8],[ebp-0x4c]
全局变量
#include “stdafx.h”
int x = 10;
void Plus()
{
int x =10;
printf("%d",x);
}
void Plus2()
{
printf("%d",x);
}
int main(int argc, char*argv[])
{
plus();
}
这样就可以在plus2打印,就是全局变量
如果把局部变量改成11
#include “stdafx.h”
int x = 10;
void Plus()
{
int x =11;
printf("%d",x);
}
void Plus2()
{
printf("%d",x);
}
int main(int argc, char*argv[])
{
plus();
plus2();
return 0;
}
输出为1111,因为11改变了全局变量的值
全局变量的特点:
在编译时地址就已经确定,只要程序启动,就会给它分内存,当exe关闭,这个值才会退出,如果没有写值,那就默认是0,重新编译后,才会变地址
全局变量的值可以被所有函数修改,里面存储最后一次修改的值
全局变量的内存会一直存在,直到整个进程结束
全局变量反汇编识别:mov 寄存器,byte/word/dword ds:[0x12345678]
全局变量就是所谓的基址
全局与局部变量总结
如图[ebp-4],[ebp-8]就是局部变量
而下面把两个的值放到eax寄存器,就是对全局变量的操作,而再下个arr的其实是dword ptr,就是把eax移到一这个arr括号里的地址
二、参数
参数传递未必通过堆栈还可能通过寄存器
比如:fastcall
push ebx
push eax
mov ecx,dword ptr ds:[]
mov ecx,dword ptr ds:[]
push 45
push 33
call 函数地址
或者有时候函数调用的代码无法查看,参数是把值从函数外面传进来给函数里面用,所以我们要看右边是寄存器的
比如右00401069的代码,我们要看的就是是不是有内存给edx赋值,函数里面没有给edx赋值,所以我们可以断定edx一定是参数
三.一堆数组的使用
要一个变量存储很多个数,要这样写int arr[10] = {1,3,7,2,8,11,5,23,22,10}
要把值取出来
如果我们这样写
void Function()
{
printf("%d\n",arr);
}
输出的是4354848
如果我们要把数取出来,代码如下
#include “stdafx.h”
void Function()
{
printf("%d\n",arr[0]);
printf("%d\n",arr[1]);
printf("%d\n",arr[2]);
printf("%d\n",arr[3]);
printf("%d\n",arr[4]);
printf("%d\n",arr[5]);
}
int main(int argc, char*argv[])
{
Function();
}
打印
1
3
7
2
8
11
找数
int x = arr[9];
printf("%d\n",x);
输出了10
四.分支语句
if语句
要打印出x和y哪个大
#include “stdafx.h”
int x = 10;
int y = 20;
void Function()
{
if(x>y)
{
printf("%d\n",x);
}
else
{
printf("%d\n",y);
}
}
int main(int argc, char*argv[])
{
Function();
}
如图,打印20
还有elseif
#include “stdafx.h”
int x = 10;
int y = 10;
void Function2()
{
if(x>y)
{
printf("%d\n",x);
}
else if(x=y)
{
printf("%s\n",'相等');
}
else
{
printf("%s\n",'y')
}
}
int main(int argc, char*argv[])
{
Function();
return 0;
}
这种情况输出“相等”
if语句逆向分析
++++++++++++
cmp:减法,根据值修改标志寄存器
所以cmp等修改标志寄存器,紧接着底下一个jcc命令就是我们说的if语句,eax小于或者等于后面那个,(但C语言写的是大于),就跳转到那个地址(C语言里就是不执行,直接跳转了),表达式不成立,才会执行下面的代码
如果写大于等于
也就是数学逻辑上的非
ifelse语句逆向
如果cmp下面的jcc指令跳,则跳转到ifelse的语句,给全局变量赋值,如果不跳进入下一次jmp直接跳到清理堆栈,跳转的到的上一行都是jmp,这些jmp跳转的地方都是清理了,如果某个分支没有判断,就是else
五.函数内部功能分析
海哥给的例题
确定上述要素后,看中间白块就行
返回值:eax里面的值