visio大法好啊,以前都是用word手动绘图的(o(╯□╰)o
调试的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| #include<stdio.h> #include<string.h> #include<stdlib.h> #include<conio.h> #define N 20 struct user { char number[N]; char password[N]; }; struct user log_In(struct user u) { int i = 0; printf("请输入用户名:\n"); gets(u.number); printf("请输入密码:\n"); while ( u.password[i] = getch() ) { if ( u.password[i] == 13 ) { break; } else if ( u.password[i] != '\b' ) { printf("*"); i++; } else { printf("\b \b"); i--; } } u.password[i] = '\0'; printf("\n"); return u; } int compare(struct user u) { FILE *fp; char file_str[2*N+1]; char *number, *password; fp = fopen("F:\\data.txt", "r"); if (!fp) { printf("error!\n"); exit(2); } while ( fgets(file_str, sizeof(file_str), fp) ) { number = strtok(file_str, " "); password = strtok(NULL, "\n"); if ( strcmp(u.number, number) == 0 && strcmp(u.password, password) == 0 ) { fclose(fp); return 1; } } fclose(fp); return 0; } int main() { struct user u; printf("--------------------------------\n"); printf("| 用户登录 |\n"); printf("--------------------------------\n"); u = log_In(u); if ( compare(u) == 1 ) printf("登录成功!\n"); else printf("登录失败!\n"); return 0; }
|
说明
上面的代码模拟的是一个登录系统,是网络对抗老师作为破解密码的例子。
我们可以在debug的时候通过单步调试,可以看到c++语言对应的汇编语言的指令。
若仅仅通过汇编语言就能明白程序的意思,这个过程叫做逆向。
这篇文章的重点是说明函数的调用机制。
先贴上自己画的原理图:
所要做的几点说明:
- 函数内存的调用就是一个栈的模型。
- 我们知道调用两个函数的时候,中间会留下一部分的空间来保存函数的返回时的信息。那么黑客就可以改变指针的方向,改变指针以达到窃取信息的目的。
补充
代码中有这样的一段:
1 2 3
| FILE *fp; char file_str[2*N+1]; char *number, *password;
|
并不是严格的按照栈的规则来存的。
可是老师课上演示的完全就是栈来存的呀。可能不同的软件分配内存的方式也是不同的吧emmmm,也有可能我使用的是c++?
对了,就连函数调用完的指示地址的指针,它的地址也是倒着存的。
内存的分配机制
分配的区域的划分:
- 栈.就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。
- 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete.如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
- 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
- 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
- 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改.
然而我也不是很懂啊,一遇到汇编语言就傻。
内存分配
几种寄存器的简单的介绍
寄存器就是能够记忆保存数据的装置。
寄存器的种类:
- EIP:程序所执行到的位置指示。
- ECP:一种计数(count)的寄存器
- EBP:内存栈的栈底(bottom)
- ESP:内存栈的栈顶(superficial?)
还有什么EAX,EDI,不是很懂。
操作的指令
- sub esp, 28h:将一个esp寄存器减去28h(16进制)
- mov ecx, 0Ah:将0Ah传输到ecx寄存器
- lea esi, [ebp-28h]:[ ]中采用相对基址变址的寻址方式表达存储单元,然后传入esi
- rep: 重复一个指令
还有很多的汇编指令,然而还不是很懂,菜菜的。
未解决的问题