memset 函数

  • 函数原型:void *memset(void *str, int c, size_t n)
  • 主要功能:复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符
  • C/C++ 实现:
#include <string.h>
#include <iostream>
#include <stdio.h>
using namespace std; int main(int argc, char ** argv)
{
char str[20] = "AAAAAAAAA";
memset(str, 'v', 10);
cout << str << endl;
return 0;
}
  • 以上程序的作用是循环复制 10 个字符 ‘v’ 到 str 所指向的字符串,执行结果:

  • 函数运行步骤:

  • 逆向分析:这个函数的作用主要是将特定的字符覆盖规定的字符串,所以首先需要取出传入 memset 函数的三个参数,并且判断第三个和第二个参数是否为 0。如果第三个参数为 0,则直接返回第一个参数所指向的字符串的首地址;如果第二个参数为 0 且第三个参数小于 100,则程序继续往下执行,反之跳出函数进行错误处理

  • 之后判断第三个参数是否小于 4,为什么要进行这个判断呢,这个先不说答案在下面。然后判断参数一传入的字符串地址是否数据对齐,如果没有对齐就对其进行对齐操作

  • 对齐判断后就开始复制字符串了,值得注意的是这里复制字符串的方式并不是循环复制 1 个字节,而是 4 个字节 4 个字节的复制,最后剩余的再每次 1 个字节的循环复制。比如我要复制 10 个字节,先循环两次复制 8 个字节,最后循环两次每次复制 1 个字节,还记得上面判断第三个参数为什么小于 4 吗,因为小于 4 的话就不必要每次 4 个字节的复制了,直接跳转到每次复制 1 个字节处即可



  • 最后将覆盖完的字符串首地址放入 eax 中,函数返回

  • 总结:memset 流程图

strcpy 函数

  • 函数原型: char *strcpy(char *dest, const char *src)
  • 作用:把 src 所指向的字符串复制到 dest
  • C/C++ 实现:
#include <string.h>
#include <iostream>
#include <stdio.h>
using namespace std; int main(int argc, char ** argv)
{
char str[20] = "AAAAAAAAA";
strcpy(str, "BBBBBB");
cout << str << endl;
return 0;
}
  • 以上程序的主要作用是将 “BB…” 复制到 str 字符串中,运行结果如图所示

  • 函数运行步骤

  • 逆向分析:首先取出传入 strcpy 函数的第一个和第二个参数



  • 之后判断第二个参数所指向的字符串是否数据对齐

  • 由于 0040121B 并不是 4 的倍数,显然数据没有对齐,从而发生跳转,进行数据对齐操作

注:对第二个参数的字符串是如何进行数据对齐操作的呢?方法简单,每次从第二个参数取出一个字符存入第一个参数指向的字符串的地址,并且第二个字符串指针加一,之后再次判断第二个参数的字符串地址是否数据对齐,如果还没有对齐就循环上述操作,直到数据对齐完毕

  • 进行完数据对齐操作之后,将第二个参数所指向的字符串循环每次复制 4 个字节到第一个参数所指向的字符串 + 2 的地址中(因为进行了对齐操作),直到这 4 个字节当中不包含 00 标志(00 表示字符串结尾)

  • 由于下面 4 个字节包含 00 字符,所以只是复制了一次

  • 最后计算出 00 字符处于 4 个字节的哪一个位置,如图所示处于第 4 个位置,故发生跳转

  • 之后把 00 字符串传入 edi 所指向的内存地址

  • 寄存器状态和内存分布如图所示:



  • strcpy 函数的流程图:

strcmp 函数

  • 函数原型:int strcmp(const char *str1, const char *str2)
  • 函数功能:把 str1 所指向的字符串和 str2 所指向的字符串进行比较(按字符的 Ascii 码进行比较)
  • C/C++ 实现:
#include <stdio.h>
#include <string.h> int main ()
{
char str1[15];
char str2[15];
int ret; strcpy(str1, "AAAaaa");
strcpy(str2, "AAaaaa"); ret = strcmp(str1, str2); if(ret < 0)
{
printf("str1 小于 str2");
}
else if(ret > 0)
{
printf("str1 大于 str2");
}
else
{
printf("str1 等于 str2");
}
return(0);
}
  • 以上程序的功能十分简单,比较 str1 和 str2 的大小,并且打印出结果。运行结果如图所示:

  • strcmp 函数运行步骤:

  • 逆向分析:首先进入 strcmp 函数,之后会取出传入 strcmp 函数的两个参数,也就是 str1 和 str2,取完参数之后判断 str1 字符串是否数据对齐,数据对齐就是 str1 字符串的首地址是否为 4 的倍数,如果 str1 字符串没有数据对齐,那么就会跳转到 0x7571938C 的地方进行数据对齐操作,在数据完成对齐后会 jmp 到 0x7571934E 的地址继续往下执行

  • 从寄存器可以看出 ecx 储存的是 str2 字符串的首地址,而 edx 储存的是 str1 字符串的首地址

  • 接下来取 str1 字符串的头四个字节放在 eax 中,之后按一个字节的大小分别与 str2 字符串相应的字符做大小比较,如果不相等就发生跳转,需要注意的时,这里比较的是 ascii 码的大小,比如 ‘A’ 字符 ascii 码为 41,而 ‘a’ 字符 ascii 码为 61,这样的话 ‘a’ 就会比 ‘A’ 字符大

  • 由于 str1 是 ‘AAAaaa’,而 str2 是 ‘AAaaaa’,所以在第三个字符比较时由于 A != a,故发生了跳转,如果前四个字节都相等的话,会将 str1 和 str2 的指针都向后指 4 个字节,在循环以上过程进行比较

  • 值得注意的是如果字符判断相等之后,如果发现 str1 对应的字符为 0(字符串结尾标志),就都会跳转到 0x75719380 这个地址,并且函数返回 0,表示字符串相等
  • 比如 str1 为 ‘Aaa’,str2 为 ‘Aaaaaa’,由于 str1 的第四个字符为 0,而前面的字符又和 str2 相等,所以判断 str1 等于 str2;但是如果 str1 为 ‘Aaaa’,而 str2 为 ‘Aaa’ 的话,则 str1 大于 str2,因为进行结尾比较的是 str1 而不是 str2,所以 str1 大于 str2

  • 最后根据 CF 标志位,以 sbb 计算的结果作为函数的返回值,如图所示 eax 的值为负数,根据 strcmp 函数的返回值文档可以看出如果函数返回值小于 0,则表示第一个参数字符串小于第二个参数字符串,也就是 str1 小于 str2

  • 为什么通过 sbb 操作指令和 CF 标志位能判断出字符串的大小呢,比如 str1 = ‘AAAA’,而 str2 = ‘AAAaaaBB’,由于前三个字符相等所以比较第四个字符,str1 的第四个字符为 A(ascii:41),而 str2 的第四个字符为 a(ascii:61),所以比较的指令就为 cmp 41,61,而 cmp 指令是根据两个操作数相减去影响标志位的,所以 41 - 61 就为负数,导致数据溢出位 CF 变为 1,而 sbb eax,eax 指令就相当于 eax - eax - CF,所以也就能比较字符的大小了
  • 那就有人问了,假如大于的话,CF 就为 0 了,岂不是两个字符串相等了吗,其实不会这样的因为在最后使用了 add eax,0x1 的操作,所以只要是大于的话返回值就会为 1,避免了和 0 之间的冲突(shl eax,1 也是同样的道理,为的是避免 add eax,0x1 在负数加一之后和 0 引发冲突)

逆向 memset、strcpy、strcmp 函数到此结束,如有错误,欢迎指正

逆向 string.h 函数库 memset、strcpy、strcmp 函数的更多相关文章

  1. 实现字符串函数,strlen(),strcpy(),strcmp(),strcat()

    实现字符串函数,strlen(),strcpy(),strcmp(),strcat() #include<stdio.h> #include<stdlib.h> int my_ ...

  2. numpy函数库中一些常用函数的记录

    ##numpy函数库中一些常用函数的记录 最近才开始接触Python,python中为我们提供了大量的库,不太熟悉,因此在<机器学习实战>的学习中,对遇到的一些函数的用法进行记录. (1) ...

  3. 逆向 string.h 函数库 strlen、memchr、strcat 函数

    strlen 函数 主要功能:返回字符串的长度 C/C++ 实现: #include <iostream> #include <stdio.h> #include <st ...

  4. 逆向 time.h 函数库 time、gmtime 函数

    0x01 time 函数 函数原型:time_t time(time_t *t) 函数功能:返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位.如果 se ...

  5. C语言中的string.h中的内存字符串处理函数

    转载请注明出处:http://blog.csdn.net/zhubin215130/article/details/8993403 void *memcpy(void *dest, const voi ...

  6. 自己实现字符串操作函数strlen(),strcat(),strcpy(),strcmp()

    1.strlen()函数是求解字符串的有效长度的 1)非递归实现 size_t my_strlen(const char *str) { assert(str != NULL);  //断言,保证指针 ...

  7. Mysql 常用函数(10)- strcmp 函数

    Mysql常用函数的汇总,可看下面系列文章 https://www.cnblogs.com/poloyy/category/1765164.html strcmp 的作用 比较两个字符串的顺序是否完全 ...

  8. 使用c函数库的两个函数strtok, strncpy遇到的问题记录

    1. strtok 问题背景: 解析形如 “1,2,3,4,5”字符串到整数数组 (1)计算个数 char* delim = ","; int count = 0; int *nu ...

  9. 13-C语言字符串函数库

    目录: 一.C语言字符串函数库 二.用命令行输入参数 回到顶部 一.C语言字符串函数库 1 #include <string.h> 2 字符串复制 strcpy(参数1,参数2); 参数1 ...

随机推荐

  1. ubantu16与windows下——redis的安装与使用

      (1) 打开ubantu16,使用如下命令下载安装包 wget http://download.redis.io/releases/redis-2.8.3.tar.gz (2)解压缩命令: tar ...

  2. SHELL编程入门简介

    一.SHELL软件概念和应用场景 1) 学习Linux技术,不是为了学习系统安装.命令操作.用户权限.配置IP.网络管理,学习Linux技术重点:基于Linux系统部署和维护各种应用软件.程序(Apa ...

  3. Java流程控制:增强for循环,break&continue,打印99乘法表

    增强for循环:java5引入了一种主要用于数组或集合的增强for循环for(声明语句:表达式){//代码句子} 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配.其作用域限定在循环语 ...

  4. android底部导航栏小结

    android自带的有TabHost,但好像无法满足要求, 本文只记录使用 TabLayout + Fragment  和 android 自带的 BottomNavigationView + Fra ...

  5. JS获取时间日期常用方法

    1 当前时间: new Date() 2 当前周: function getCurrentWeek() { var date = new Date() var beginDate = new Date ...

  6. sitemesh简单介绍

    SiteMesh 是一个网页布局和修饰的框架,利用它可以将网页的内容和页面结构分离,以达到页面结构共享的目的. Sitemesh是由一个基于Web页面布局.装饰以及与现存Web应用整合的框架. 它能帮 ...

  7. 2018.12-2019.1 TO-DO LIST

    AC自动机 P3808 [模板]AC自动机(简单版)(完成时间:2018.12.06) P3796 [模板]AC自动机(加强版)(完成时间:2018.12.06) P2444 [POI2000]病毒( ...

  8. c++ vector容器浅析

    注:本文章参考 https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html 前言: 最近遇到一个广搜的题,不管怎么试都会暴 然后 ...

  9. 【设计模式】- 生成器模式(Builder)

    生成器模式 建造者模式.Builder 生成器模式 也叫建造者模式,可以理解成可以分步骤创建一个复杂的对象.在该模式中允许你使用相同的创建代码生成不同类型和形式的对象. 生成器的结构模式 生成器(Bu ...

  10. 可读性友好的JavaScript:两个专家的故事

    每个人都想成为专家,但什么才是专家呢?这些年来,我见过两种被称为"专家"的人.专家一是指对语言中的每一个工具都了如指掌的人,而且无论是否有帮助,都一定要用好每一点.专家二也知道每一 ...