看了一下windows的内核与原理的目录,开始的学习
需要记住:
包括网络子系统,设备管理子系统,内存管理子系统,BIOS加载,调试子系统,GUI子系统,远程通信子系统,存储管理子系统,中断管理子系统。
学习到
windows系统常用动态链接库,比如kernel32.dll,user32.dll等
PEiD工具
首先什么是PE文件?
PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)
PE文件是指32位可执行文件,也称为PE32。64位的可执行文件称为PE+或PE32+,是PE(PE32)的一种扩展形式(请注意不是PE64)。
PE 文件结构说明:
DOS头 是用来兼容 MS-DOS 操作系统的,目的是当这个文件在 MS-DOS 上运行时提示一段文字,
大部分情况下是:This program cannot be run in DOS mode. 还有一个目的,
就是指明 NT 头在文件中的位置。
NT头 包含 windows PE 文件的主要信息,其中包括一个 'PE' 字样的签名,PE文件头(IMAGE_FILE_HEADER)和 PE可选头(IMAGE_OPTIONAL_HEADER32)。
节表:是 PE 文件后续节的描述,windows 根据节表的描述加载每个节。
节:每个节实际上是一个容器,可以包含 代码、数据 等等,每个节可以有独立的内存权限,
比如代码节默认有读/执行权限,节的名字和数量可以自己定义,未必是上图中的三个。
转载自:https://blog.csdn.net/freeking101/article/details/102752048
DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。
了解上面的东西
再来看这
程序在加载到内存的时候,会去读取PE的导入表,把运行需要的动态链接库,载入到内存,然后修正对应函数的地址,之后才把程序入口放入EIP指针
而用PEiD工具
查看PE文件的,导入导出表结构的东西
而影响PE加载的一个点就是导入表
导入表中,包含了该PE文件需要引用的所有外部函数,而PE加载后,加载器会把该PE的所有需要用的DLL载入到内存中。如果有某个函数找不到所需的DLL,则PE文件就会加载失败。
Ag样例
int main()
{double a = 0, b = 0;double c = 0;char ch = 0;UINT c_a = sizeof(a), c_b = sizeof(b), c_ch = sizeof(ch);//scanf_s("%1f",&a,c_a);scanf_s("%c",&ch, c_ch);scanf_s("%lf", &b, c_b);switch (ch){case'+':c = a + b; printf("%.2f", c);break;case'-':c = a - b; printf("%.2f", c);break;case'*':c = a * b; printf("%.2f", c);break;case'/':if (b != 0) {c = a / b; printf("%.2f", c);}else {printf("除数不能为0");}break;default:printf("运算符有误");}return 0;
}
从这个代码,编译器出来的函数会用到多少个系统的API函数?
API(Application Programming Interface,应用程序编程接口)
API 就是应用程序编程接口。 它是能用来操作组件、应用程序或者操作系统的一组函数。 典型的情况下,API 由一个或多个提供某种特殊功能的 DLL 组成。 [2] API函数包含在Windows系统目录下的 动态连接库 文件中。 Windows API是一套用来控制Windows的各个部件的外观和行为的预先定义的Windows函数。
简单点就是这段代码里面用到多少函数
我最开始光从这个代码来看就是5个
现在我们用工具来看看
把样本拖入
点击子系统
点开输入列表
我们看到有三个系统的DLL
点击,可一个dLL名字,下边的列表就是PE文件中该模块用到的函数
点开第一个dll文件
原来我们程序的代码只有几个函数,而在这里我们看到,有这么多API函数
为什么?
因为编译器对代码进行了包装
而且这些函数底层会调用多个系统函数来实现功能的
这么理解
我在编译器里面看到使用的函数,其实是这些函数被包装起来了
从而成了一个函数集合
构造一个新的函数
再次使用而已
这个就是代码复用
问题来了
既然,一个函数,会调用多个底层函数实现功能,那么有没有可能我们自己使用底层函数实现功能,而不使用现成的接口呢?
那得需要了解底层这些函数的具体功能,才会有可能。
那么逆向就有用了
一般还原功能功能,都是通过逆向搞清楚每个底层函数的参数和逻辑,然后自己写出来
现在用IDA32位打开
凡是80386一定就是32位,无论用什么端口打开
通过Ctrl+E我们可以快速找到入口
但我们程序实际的入口是主函数
通过引用,跳转,看看到start 一共经历了多少个函数调用
因为还不是很熟
4124A0
412100
412120
412272
4123F0
4112DA
411930
这是学长找到的一共是这么多层
我只看懂了两层
其他的没懂
从start 到 main 这个中间,这些都是VS包的,很多运行环境检查的代码
#include
#include#pragma warning(disable:4996)
int main()
{double a = 0, b = 0;double c = 0;char ch = 0;UINT c_a = sizeof(a), c_b = sizeof(b), c_ch = sizeof(ch);scanf_s("%lf%c%lf",&a,&ch,1,&b);switch (ch){case'+':c = a + b; printf("%.2f", c);break;case'-':c = a - b; printf("%.2f", c);break;case'*':c = a * b; printf("%.2f", c);break;case'/':if (b != 0) {c = a / b; printf("%.2f", c);}else {printf("除数不能为0");}break;default:printf("运算符有误");}return 0;
}
之前这个代码在VS上用不了
主要是是因为scanf函数的问题
scanf 有个隐藏参数
就是char 和 wchar 或者数组类型,需要提供长度参数,除此之外,都不需要填写第二个参数
以及今天才明白scanf_s
在后面要提供长度参数
当然为什么后面改用scanf_s函数
主要scanf函数有栈的溢出问题
error C4996: ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
明白了两个定义的区别
因为版本原因我们想在VS上用以前版本的函数
所以要加上定义,而下面这两条都可以对于scanf函数
但是有区别
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
第一个是完全关闭检查
第二个只是排除目前这一个状态
明晚学习:
用OD,调试这个二进制
熟悉一下,操作系统调试