回顾了下,以前学的一些东西,好旧,不过基本知识点没变~~为了破解个游戏学逆向,容易吗我?
有些忘了,看汇编还是很吃力,玩了2天好些,至少知道怎么找到main函数段了(一般在开头,不过不同编译器不一样,而且debug跟release汇编出来的也不同)
再接再厉!
原来变量名只是定义给编译器看的……最终机器码没有,有的只是地址。
主函数也是子程序。由编译器负责链接咱程序生成的obj并最先调用。如果把那个链接的obj改了,自己弄个让它调用别的,也可以没有main。(TC2.0的那个obj是c0s.obj,咱程序的obj就接在c0s.obj里面的后部)。C语言的提供的obj用于我们自写的程序的初始化和返回等相关操作。
全局变量存内存里可以直接访问,局部变量压在一个地址存在bp寄存器的栈里。所有函数(包括main)一被调用,先push保留原先bp的值,然后让bp指向栈顶,函数调用完毕,bp被pop还原,就找不到局部变量的位置了。
float首位为符合位,记之后八位值减127的值为a,然后得到整数部分是2^a,剩下的是尾数,如1.5(10),首先声明0.5(10)=0.1(2),则1.5(10)=2^0+0.5=2^(127-127)+0.5=0|011 1111 1|100 0000 0000 0000 0000 0000(2)=3FC0 0000(16),故dx为3FC0h,ax为0000h,。
当传递参数较多,使用堆栈,参数一个个自右向左根据大小赋给al,ax,dx。然后push。不定个参数居然可以这样void show(...);!!!不过你得保证能让函数得到参数个数。
不得不佩服编译器牛逼,越来越好玩了。
高级语言中的乘除法:
我个人认为应该是用移位来实现的,于是模拟了一下乘法打了一段移位乘法,结果跟直接a*b相同,一样的溢出。当然,这段东西有待改善,感觉多余了不少东西,比如移位后又移回来,回家后再优化吧。
代码如下:
第一组数据共同溢出了,第二组得到正确结果。
原来变量名只是定义给编译器看的……最终机器码没有,有的只是地址。
主函数也是子程序。由编译器负责链接咱程序生成的obj并最先调用。如果把那个链接的obj改了,自己弄个让它调用别的,也可以没有main。(TC2.0的那个obj是c0s.obj,咱程序的obj就接在c0s.obj里面的后部)。C语言的提供的obj用于我们自写的程序的初始化和返回等相关操作。
全局变量存内存里可以直接访问,局部变量压在一个地址存在bp寄存器的栈里。所有函数(包括main)一被调用,先push保留原先bp的值,然后让bp指向栈顶,函数调用完毕,bp被pop还原,就找不到局部变量的位置了。
例如:
#include <stdio.h>
int main()
{
int a;
scanf("%d",&a);
printf("%d",a/11);
return 0;
}
用vs2010的release编译后,用OD查看C++作业.exe如下(蓝色注释):
函数返回值char(1字节)存在al;int(2字节)存在寄存器ax里;long(4字节)存dx,ax;float同long,不过较复杂(琢磨半饷,可能不对)……
float首位为符合位,记之后八位值减127的值为a,然后得到整数部分是2^a,剩下的是尾数,如1.5(10),首先声明0.5(10)=0.1(2),则1.5(10)=2^0+0.5=2^(127-127)+0.5=0|011 1111 1|100 0000 0000 0000 0000 0000(2)=3FC0 0000(16),故dx为3FC0h,ax为0000h,。
当传递参数较多,使用堆栈,参数一个个自右向左根据大小赋给al,ax,dx。然后push。不定个参数居然可以这样void show(...);!!!不过你得保证能让函数得到参数个数。
不得不佩服编译器牛逼,越来越好玩了。
高级语言中的乘除法:
我个人认为应该是用移位来实现的,于是模拟了一下乘法打了一段移位乘法,结果跟直接a*b相同,一样的溢出。当然,这段东西有待改善,感觉多余了不少东西,比如移位后又移回来,回家后再优化吧。
代码如下:
#include <iostream>
using namespace std;
int main()
{
int a,b,mul;
while(cin>>a>>b)
{
__asm
{
mov eax,a
mov ecx,b
mov edx,0
L:
jcxz ok
shr ecx,1
pushf
shl eax,1
popf
jnc L
shr eax,1
add edx,eax
shl eax,1
jmp L
ok:
mov mul,edx
}
cout<<a*b<<' '<<mul<<endl;
}
}
第一组数据共同溢出了,第二组得到正确结果。