逆向 stdio.h 函数库 fseek 函数(调试版本)
0x01 fseek 函数
- 函数原型:
int fseek(FILE *stream, long int offset, int whence) - 函数功能:设置流
stream的文件位置为给定的偏移offset,参数offset意味着从给定的whence位置查找的字节数 - 动态链接库:
ucrtbased.dll - C\C++ 实现:
#define _CRT_SECURE_NO_WARNINGS // 抛弃安全警告
#include <stdio.h>
#include <string.h>
int main()
{
FILE* fp;
fp = fopen("D:\\1.txt", "w+");
fputs("This is runoob.com", fp);
fseek(fp, 7, SEEK_SET);
fputs(" C Programming Langauge", fp);
fclose(fp);
return(0);
}
- 上述程序的功能主要是打开
D:\1.txt文件,之后调整文件流的偏移,最后关闭文件 - 调试工具:
x32dbg调试器 - 逆向分析:首先利用定位字符串的方式找到
fseek函数

fseek(一级函数)中调用了两个子函数:ucrtbased.sub_625FF510负责将传入的参数一(文件句柄)赋值到局部变量[ebp-4]中,之后压入文件句柄调用ucrtbased.sub_6261C940

ucrtbased.sub_6261C940(二级函数)函数内部首先判断传入的第一个参数(文件句柄)是否存在,不存在的话就调用_CrtDbgReportW和_error进行错误处理

- 之后判断传入的第四个参数(
SEEK_SET)是否为0、1、2中的一个

SEEK_SET: 文件开头 0
SEEK_CUR: 当前位置 1
SEEK_END: 文件结尾 2
- 然后调用
ucrtbased.sub_ 625EC550获取文件句柄,文件句柄的类型为FILE。紧接着调用_lock_file锁住文件。既然锁住了文件,那么肯定要解锁文件,如图所示:解锁文件的函数_unlock_file在结尾处调用

- 最后压入参数调用
ucrtbased.sub_6261CCE0(三级函数),参数如下图注释所示

- 进入
ucrtbased.sub_6261CCE0(三级函数) 函数单步调试:首先会调用ucrtbased.sub_62616B10和ucrtbased.sub_626168F0对_flag进行判断

- 注:
_flag是_iobuf结构体的成员,而FILE结构体指针指向的原型就是_iobuf。结构体示意图如下图所示:
ucrtbased.sub_62616B10:判断(_flag & 2000)是否大于0,若等于0,则函数直接返回。因为查阅不到_flag成员的有关资料,所以暂时不知道这一步操作是什么目的
ucrtbased.sub_626168F0判断方式:先循环比较_flag和(_flag & FFFFFFF7)是否相等,然后比较_flag & 8是否等于0。这里有两个bug,假如_flag为204e的话,就变成死循环了。而且通过观察ucrtbased.sub_626168F0的返回值,发现没有对返回值做任何处理,也就是说这个判断_flag的函数没有任何作用
- 然后压入 4 个参数后,调用
ucrtbased.sub_6261CB00(四级函数)

- 进入
ucrtbased.sub_6261CB00(四级函数)函数进行分析:首先这个函数判断传入的第四个参数(SEEK_SET)是否为指向文件结尾,如果指向文件结尾此函数返回0,之后调用ucrtbased.sub_62615130和ucrtbased.sub_62615150对 _flag 进行判断

- 注
ucrtbased.sub_62615130的判断方式:(_flag & 4c0) 是否等于0,若不等于0,返回1
ucrtbased.sub_62615150的判断方式:在 (_flag & 4c0) 是不等于0的前提下判断 (_flag & 6) 是否等于0,若不等于0,返回1
ucrtbased.sub_62615150判断完成之后直接清空eax,ucrtbased.sub_6261CB00(四级函数)返回

- 返回之后判断传入的第四个参数(
SEEK_SET)是否为当前文件位置,由于不是当前文件位置,故发生了跳转

- 之后调用
ucrtbased.sub_625EC550获取文件句柄,把文件句柄做为参数压入,接着调用ucrtbased.sub_62619070

ucrtbased.sub_62619070(四级函数) 这个函数主要是对_iobuf->cnt和_iobuf->*_ptr进行操作,进入这个函数看看:首先会调用ucrtbased.sub_625FF510将文件句柄赋值到局部变量[ebp-4]当中,接着调用ucrtbased.sub_62615070将取出_iobuf->_flag取出

- 注:
ucrtbased.sub_62619010是对_iobuf->_flag进行判断
- 判断方式:
if((_flag & 3 == 2) && (_flag & C0 == 0))
{
return 1;
}
else
{
return 0;
}
- 判断完成之后,将
_iobuf->*_ptr - _iobuf->_cnt,

- 接着调用
ucrtbased.sub_62618EA0,该函数的主要功能:_iobuf->*ptr = iobuf->cnt,并将_iobuf->*_base赋值为0

- 之后在
_iobuf->*ptr - _iobuf->_cnt大于0的前提下调用_fileno和_write函数

- 之后再判断写入的字节和
_iobuf->*ptr - _iobuf->_cnt相等的前提下调用ucrtbased.sub_62618FA0,该函数的主要功能就是判断_iobuf->_flag & 4和4是否相等,eax返回1表示相等


- 最后调用
ucrtbased.sub_62618FA0判断_flag & 8是否等于0,ucrtbased.sub_62619070(四级函数)返回0 - 接着向下调试,发现会将
_iobuf->*ptr赋值为iobuf->cnt,_iobuf->*_base设置为0,并且判断_iobuf->flag & 4和4是否相等, 再相等的前提下判断_flag & 8是否为0

- 最后调用
ucrtbased.sub_62619070(四级函数)

- 进入这个函数看看:首先会使用
_get_osfhandle检索与指定文件描述符关联的操作系统文件句柄,如果函数调用失败则进入错误处理

- 之后调用
ucrtbased.sub_62619070

- 这个函数的功能是利用
SetFilePointerEx函数移动指定文件的文件指针,并配合GetLastError函数进行错误处理
- 接着将返回值放入局部变量中

- 最后返回


- 在
ucrtbased.sub_6261ccE0的结尾对这两个返回值进行比较,如图所示跳转实现,故返回值为0

- 最后使用
_unlock_file对文件进行解锁,fseek函数调用结束

逆向 stdio.h 库的
fseek函数到此结束,如有错误,欢迎指正
逆向 stdio.h 函数库 fseek 函数(调试版本)的更多相关文章
- 逆向 stdio.h 函数库 fwrite 函数(调试版本)
0x01 fwrite 函数 函数原型: size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 函数功能:把 ...
- 逆向 stdio.h 函数库 fopen 函数(调试版本)
0x01 fopen 函数 函数原型:FILE *fopen(const char *filename, const char *mode) 返回值为 FILE 类型 函数功能:使用给定的模式 mod ...
- php使用file函数、fseek函数读取大文件效率分析
php读取大文件可以使用file函数和fseek函数,但是二者之间效率可能存在差异,本文章向大家介绍php file函数与fseek函数实现大文件读取效率对比分析,需要的朋友可以参考一下. 1. 直接 ...
- 走进C标准库(2)——"stdio.h"中的fopen函数
其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...
- strtok()函数、fseek()函数、fwrite()函数、fread()函数的使用
在电子词典这个项目过程中遇到了几个主要的问题,第一个是怎么解决把翻译分开这个.第二个事情就是怎么把结构体写到文件中.这两个问题,一个是关于字符串的操作一个是关于文件的操作. strtok函数 char ...
- python函数库及函数标准库
一.系统库提供的内部函数 字符函数库: 1)str.islower() :字符串是否全部是小写 2)str.isspace() :字符串是否为空 3)help(str):查询字符串函数库 4)str. ...
- C函数库stdio.h概况
库变量 size_t 这是无符号整数类型,它是 sizeof 关键字的结果. FILE 这是一个适合存储文件流信息的对象类型. fpos_t 这是一个适合存储文件中任何位置的对象类 ...
- C语言函数库
C语言函数库 分类函数目录函数进程函数诊断函数接口子程序输入输出 str字符串操作函数mem操作存贮数组 数学函数 时间日期函数 转换函数 分类函数,所在函数库为ctype.h[top] int is ...
- C 标准库 - <stdio.h>
一般地,在C语言或C++中,会把用来#include的文件的扩展名叫 .h,称其为头文件. #include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体 ...
随机推荐
- mysql查询缓存简单使用
MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBM ...
- Python中OS对目录的操作以及引用
路径的获取 对当前目录的获取 1 path = os.getcwd() 2 print("获取到的当前目录是:({})".format(path)) 获取当前文件所在的绝对路径 i ...
- 【Arduino学习笔记01】关于Arduino引脚的一些笔记
参考链接:https://www.yiboard.com/thread-831-1-1.html Arduino Uno R3 - 引脚图 Arduino Uno R3 - 详细参数 Arduino ...
- MyBatis架构分析
我们都知道Mybatis是一个非常小巧灵活的ORM框架,深受国内广大开发者的喜爱,我们知道它的出现某种程度是为了消除所有的JDBC代码和参数的手工设置以及结果集的封装问题:基于这个一点,我们就可以 ...
- docker+compose+nginx+php
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 我用docker做什么? 快速搭建开发所需环境,测试实验新 ...
- This is my first blog----文件操作基本流程
一,文件操作基本流程. 计算机系统分为: 计算机硬件, 操作系统, 应用程序三部分 我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件 ...
- POJ_2452 Sticks Problem 【ST表 + 二分】
一.题目 Sticks Problem 二.分析 对于$i$和$j$,并没有很好的方法能同时将他们两找到最优值,所以考虑固定左端点$i$. 固定左端点后,根据题意,$a[i]$是最小值,那么现在的问题 ...
- Hexagon HDU - 6862
题目链接:https://vjudge.net/problem/HDU-6862 题意: 由六边形组成的圆形图案,要求不重复走遍历每一个小六边形. 思路:https://www.cnblogs.com ...
- LookupError: 'hex' is not a text encoding; use codecs.decode() to handle arbitrary codecs
问题代码: b=b'\x01\x02\x03' x=binascii.b2a_hex(b.decode('hex')[::-1].encode('hex')) python2下是不报错的,因为pyth ...
- Ubuntu20.04linux内核(5.4.0版本)编译准备与实现过程-编译前准备(1)
最近项目也和linux kernel技术有关,调试内核和内核模块.修改内核源码,是学习内核的重要技术手段之一.应用这些技术时,都有一本基本的要求,那就是编译内核.因此,在分析内核调试技术之前,本随笔给 ...





