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_62616B10ucrtbased.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,假如 _flag204e 的话,就变成死循环了。而且通过观察 ucrtbased.sub_626168F0 的返回值,发现没有对返回值做任何处理,也就是说这个判断 _flag 的函数没有任何作用

  • 然后压入 4 个参数后,调用 ucrtbased.sub_6261CB00(四级函数)

  • 进入 ucrtbased.sub_6261CB00(四级函数)函数进行分析:首先这个函数判断传入的第四个参数(SEEK_SET)是否为指向文件结尾,如果指向文件结尾此函数返回 0,之后调用 ucrtbased.sub_62615130ucrtbased.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 判断完成之后直接清空 eaxucrtbased.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 & 44 是否相等,eax 返回 1 表示相等



  • 最后调用 ucrtbased.sub_62618FA0 判断 _flag & 8 是否等于 0ucrtbased.sub_62619070(四级函数)返回 0
  • 接着向下调试,发现会将 _iobuf->*ptr 赋值为 iobuf->cnt_iobuf->*_base 设置为 0,并且判断 _iobuf->flag & 44 是否相等, 再相等的前提下判断 _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 函数(调试版本)的更多相关文章

  1. 逆向 stdio.h 函数库 fwrite 函数(调试版本)

    0x01 fwrite 函数 函数原型: size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 函数功能:把 ...

  2. 逆向 stdio.h 函数库 fopen 函数(调试版本)

    0x01 fopen 函数 函数原型:FILE *fopen(const char *filename, const char *mode) 返回值为 FILE 类型 函数功能:使用给定的模式 mod ...

  3. php使用file函数、fseek函数读取大文件效率分析

    php读取大文件可以使用file函数和fseek函数,但是二者之间效率可能存在差异,本文章向大家介绍php file函数与fseek函数实现大文件读取效率对比分析,需要的朋友可以参考一下. 1. 直接 ...

  4. 走进C标准库(2)——"stdio.h"中的fopen函数

    其他的库文件看起来没有什么实现层面的知识可以探究的,所以,直接来看stdio.h. 1.茶余饭后的杂谈,有趣的历史 在过去的几十年中,独立于设备的输入输出模型得到了飞速的发展,标准C从这个改善的模型中 ...

  5. strtok()函数、fseek()函数、fwrite()函数、fread()函数的使用

    在电子词典这个项目过程中遇到了几个主要的问题,第一个是怎么解决把翻译分开这个.第二个事情就是怎么把结构体写到文件中.这两个问题,一个是关于字符串的操作一个是关于文件的操作. strtok函数 char ...

  6. python函数库及函数标准库

    一.系统库提供的内部函数 字符函数库: 1)str.islower() :字符串是否全部是小写 2)str.isspace() :字符串是否为空 3)help(str):查询字符串函数库 4)str. ...

  7. C函数库stdio.h概况

    库变量 size_t    这是无符号整数类型,它是 sizeof 关键字的结果. FILE      这是一个适合存储文件流信息的对象类型. fpos_t   这是一个适合存储文件中任何位置的对象类 ...

  8. C语言函数库

    C语言函数库 分类函数目录函数进程函数诊断函数接口子程序输入输出 str字符串操作函数mem操作存贮数组 数学函数 时间日期函数 转换函数 分类函数,所在函数库为ctype.h[top] int is ...

  9. C 标准库 - <stdio.h>

    一般地,在C语言或C++中,会把用来#include的文件的扩展名叫 .h,称其为头文件. #include文件的目的就是把多个编译单元(也就是c或者cpp文件)公用的内容,单独放在一个文件里减少整体 ...

随机推荐

  1. 如何实现一个简易版的 Spring - 如何实现 @Autowired 注解

    前言 本文是 如何实现一个简易版的 Spring 系列第四篇,在 上篇 介绍了 @Component 注解的实现,这篇再来看看在使用 Spring 框架开发中常用的 @Autowired 注入要如何实 ...

  2. NumPy 将停止支持 Python 2

    NumPy 项目宣布将停止支持 Python 2.Python 核心团队已经决定在 2020 年停止支持 Python 2,而 NumPy 项目自 2010 年以来同时支持 Python 2 和 Py ...

  3. Java多线程之线程

    前言 线程作为现代操作系统调度的最小单元,多个线程能够同时执行,这将显著提高程序的性能,而且在当前多核CPU的环境下也能更好的利用资源.Java提供了对多线程的良好支持.线程是多线程的基础. 使用多线 ...

  4. pandas函数高级

    一.处理丢失数据 有两种丢失数据: None np.nan(NaN) 1. None None是Python自带的,其类型为python object.因此,None不能参与到任何计算中. #查看No ...

  5. 前端坑多:使用js模拟按键输入的踩坑记录

    坑 一开始在Google搜索了一番,找到了用jQuery的方案,代码量很少,看起来很美好很不错,结果,根本没用-- 我反复试了这几个版本: var e = $.Event('keyup') e.key ...

  6. 【体系结构】Oracle进程架构

    Client Process的介绍 Client and Server Processes Client Process代表着客户端进程,每一个客户端进程关联着一个Server Process(服务器 ...

  7. 【Django笔记0】-Django项目创建,settings设置,运行

    Django项目创建,settings设置,运行 1,项目创建 ​ 通过pip下载Django以后,在cmd中cd到想要创建项目的路径,之后输入: django-admin startproject ...

  8. Python的多进程和多线程

    进程和线程 进程是系统进行资源分配的最小单位,线程是系统进行调度执行的最小单位: 一个应用程序至少包含一个进程,一个进程至少包含一个线程: 每个进程在执行过程中拥有独立的内存空间,而一个进程中的线程之 ...

  9. vue封装公用弹出框方法,实现点击出现操作弹出框

    vue封装公用弹出框方法,实现点击出现操作弹出框 如上图所示,这次要实现一个点击出现操作弹框的效果:并将这个功能封装成一个函数,便于在项目的多个地方使用. 具体思路是: 封装一个组件,组件保护一个插槽 ...

  10. vue之mixin理解与使用

    使用场景 当有两个非常相似的组件,除了一些个别的异步请求外其余的配置都一样,甚至父组件传的值也是一样的,但他们之间又存在着足够的差异性,这时候就不得不拆分成两个组件,如果拆分成两个组件,你就不得不冒着 ...