逆向 stdio.h 函数库 fwrite 函数(调试版本)
0x01 fwrite 函数
- 函数原型:
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
- 函数功能:把
ptr
所指向的数组中的数据写入到给定流stream
中 - 动态链接库:
ucrtbased.dll
- C\C++ 实现:
#define _CRT_SECURE_NO_WARNINGS // 用于排除安全限制
#include <stdio.h>
#include <string.h>
int main()
{
FILE* fp;
char c[] = "This is runoob";
char buffer[20];
/* 打开文件用于读写 */
fp = fopen("D:\\1.txt", "w+");
/* 写入数据到文件 */
fwrite(c, strlen(c) + 1, 1, fp);
/* 查找文件的开头 */
fseek(fp, 0, SEEK_SET);
/* 读取并显示数据 */
fread(buffer, strlen(c) + 1, 1, fp);
printf("%s\n", buffer);
fclose(fp);
return(0);
}
- 上述程序主要的功能就是打开路径为
D:\1.txt
文件,之后将字符串This is runoob
写入文件后,再读取。运行结果如下图所示:
- 调试工具:
x32dbg
- 逆向分析:要分析
fwrite
函数首先需要定位函数的位置,由于这个程序比较简单,所以直接定位main
函数即可。如下图所示通过直接定位字符串This is runoob
就可以找出main
函数的位置
- 在
main
函数中看出有几个重要的API
函数,例如:fopen、strlen、fwrite、fread
这几个函数
- 而本次分析的是
fwrite
函数,因此直接定位到该函数,传入的参数如下图注释所示。需要注意的是字符串的长度是通过上面的strlen
函数获取的,而文件的句柄是通过fopen
函数获得的
- 进入
fwrite
函数进行分析。首先会对传入的参数进行过滤(这也是一些API
函数的通用流程),判断传入的字符串、文件句柄、元素的个数是否为0
,也就是是否存在的意思。如果有一个条件不符合就会调用ucrtbased._CrtDbgReportW
函数做错误处理或直接清空eax
返回
- 继续向下调试,发现会调用
ucrtbased.sub_F538CD0
函数,这个函数的功能比较简单,就是将传入fwrite
的参数赋值到[ebp-18]
这个局部变量当中,为了方便起见将这个局部变量取名为fileinfo
,而且根据赋值的特征,这个fileinfo
很有可能是一个结构体
- 紧接着调用
ucrtbased.sub_F53DF10
函数,压入的第一个参数为文件的句柄(fopen
函数的返回值,类型为FILE
),第二个参数为fileinfo
结构体
- 进入
ucrtbased.sub_F53DF10
函数,可以看出这个函数调用了三个子函数。第一个函数ucrtbased.sub_F51F4C0
的功能是将传入的参数一(文件句柄)放入局部变量[ebp-8]
中,第二个参数ucrtbased.sub_F51F4C0
的功能是将文件句柄赋值到局部变量[ebp-c]
当中去。之后压入[ebp-8]
后调用ucrtbased.sub_F53DE80
函数,需要注意的是,这里还有一个局部变量[ebp-1]
,通过ecx
传入的
- 进入
ucrtbased.sub_F53DE80
函数,发现这个函数会调用4
个子函数,第一个函数ucrtbased.sub_F538D10
的功能是调用_lock_file
API
函数来锁住文件,为的是为接下来写入文件做铺垫,而传入ucrtbased.sub_F53DE80
函数的参数是通过[ebp+8]
来获取的,也就是文件句柄
- 既然通过了
_lock_file
来锁住文件那么之后肯定需要解锁文件,解锁文件的系统API
函数是_unlock_file
,由该函数中的ucrtbased.sub_F538D30
函数调用
- 而
ucrtbased.sub_F53DF50
函数才是实现fwrite
功能的核心函数,传入此函数的参数如下图中的注释所示
ucrtbased.sub_F53DF50
函数中调用了 3 个子函数
- 第一个函数
ucrtbased.sub_F53AF70
,主要功能是判断文件描述符是否于指定设备想关联
- 主要用到了
_fileno
和_isatty
两个API
来判断,如果未关联就返回_isatty
的返回值,如果没有就做一些处理,由于处理涉及调式和未调试的区别,比较复杂,所以不多述
- 进行完设备关联判断之后,调用
_fwrite_nolock
这个API
函数将传入的字符串写入规定的文件流,传入的参数如图所示,返回值储存在[ebp-8]
中
- 最后看一下
ucrtbased.sub_F53AFA0
函数
- 在这个函数内部首先会判断传入的第一个参数是否为
0
,根据实际的运行流程在test ecx,ecx
命令判断之后直接实现了跳转,函数直接返回了。为了详细的了解程序,还是看了一下这几个函数都调用了哪些 API 函数,经过查找后发现在ucrtbased.sub_F539070
函数中调用了_fileno
和_write
,这个和上面处理的流程还是蛮类似的
- 最后函数返回,返回值就是
_fwrite_nolock
函数的返回值
- 最后完成对
fwrite
函数的调用
- 函数运行流程:
开始->参数过滤->_lock_file->_file_no->_isatty->_fwrite_nolock->unlock_file->结束
逆向 stdio.h 库的
fwrite
函数到此结束,如有错误,欢迎指正
逆向 stdio.h 函数库 fwrite 函数(调试版本)的更多相关文章
- 逆向 stdio.h 函数库 fseek 函数(调试版本)
0x01 fseek 函数 函数原型:int fseek(FILE *stream, long int offset, int whence) 函数功能:设置流 stream 的文件位置为给定的偏移 ...
- 逆向 stdio.h 函数库 fopen 函数(调试版本)
0x01 fopen 函数 函数原型:FILE *fopen(const char *filename, const char *mode) 返回值为 FILE 类型 函数功能:使用给定的模式 mod ...
- 走进C标准库(2)——"stdio.h"中的fopen函数
其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...
- fopen函数和fread函数、fwrite函数
fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const ...
- 【转】fread函数和fwrite函数
1.函数功能 用来读写一个数据块. 2.一般调用形式 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp); 3.说明 ( ...
- strtok()函数、fseek()函数、fwrite()函数、fread()函数的使用
在电子词典这个项目过程中遇到了几个主要的问题,第一个是怎么解决把翻译分开这个.第二个事情就是怎么把结构体写到文件中.这两个问题,一个是关于字符串的操作一个是关于文件的操作. strtok函数 char ...
- fread函数和fwrite函数
1.函数功能 用来读写一个数据块. 2.一般调用形式 fread(buffer,size,count,fp); fwrite(buffer,size,count,fp); 3.说明 ( ...
- python函数库及函数标准库
一.系统库提供的内部函数 字符函数库: 1)str.islower() :字符串是否全部是小写 2)str.isspace() :字符串是否为空 3)help(str):查询字符串函数库 4)str. ...
- C函数库stdio.h概况
库变量 size_t 这是无符号整数类型,它是 sizeof 关键字的结果. FILE 这是一个适合存储文件流信息的对象类型. fpos_t 这是一个适合存储文件中任何位置的对象类 ...
随机推荐
- 第01章-Java SE8的流库
从迭代到流的操作 流表面上看起来和集合很类似,都可以让我们转换和获取数据,但是它们之间存在着显著的差异 流并不存储其元素,这些元素可能存储在底层的集合中,或者是按需生成的 流的操作不会修改其数据源 流 ...
- Spark性能调优-RDD算子调优篇(深度好文,面试常问,建议收藏)
RDD算子调优 不废话,直接进入正题! 1. RDD复用 在对RDD进行算子时,要避免相同的算子和计算逻辑之下对RDD进行重复的计算,如下图所示: 对上图中的RDD计算架构进行修改,得到如下图所示的优 ...
- TiDB在更新版本的时候初始化Prometheus的配置文件失败
一.背景是更换版本了之后,按照正常扩容节点也会报错. 我们安装的TiDB版本是v4.0.0,因为环境还在试用阶段,所以会经常增删节点.原因是我们违背官方说明,强行用机械盘上了,跑不过单机的mysql, ...
- FreeBSD WIFI 配置详细介绍
首先运行ifconfig,看看能不能找到你的网卡,如果能,那么你可以走了﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉运行sysctl net.wlan.devices,他可以告诉你,找到的无线网卡编辑/b ...
- 设计模式之建造者模式(BuilderPattern)
一.意义 将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 说明:复杂对象的构建,比如一个对象有几十个成员属性,那么我们在创建这个对象,并给成员属性赋值时,就会很麻烦.采用 ...
- P1071 潜伏者(JAVA语言)
//HashMap大法好 题目描述 RR国和SS国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动.历尽艰险后,潜伏于SS国的RR 国间谍小CC终于摸清了 SS 国军用密码的编码规则: 1. S ...
- 剪切DOM节点中断transition执行【问题】
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- CentOS7使用NTP搭建时间同步服务器
前言 为什么要搭建时间同步服务器呢?场景是这样的. 我们有两台CentOS服务器,其中一台是可以连接外网的,下文中我们称它为A服务器,另一台不能连接外网,但是与A服务器在同一局域网中,下文中我们称它为 ...
- nginx提供网站首页的一个实例
如果既想匹配'/'进行反向代理,同时又想通过nginx提供网站首页,可以在server中进行如下配置: user python; # 运行Nginx的用户 worker_processes auto; ...
- List集合中的交集 并集和差集
目录 List集合求交集 并集 差集 Set集合 Lambda表达式 List集合求交集 并集 差集 两种方法求集 Set集合 交集 两个集合中有相同的元素 抽取出来的数据就是为交集 @Test pu ...