首页 > 其他分享 >BUUCTF-reverse3

BUUCTF-reverse3

时间:2024-12-20 19:56:17浏览次数:10  
标签:BUUCTF 41A144 v12 int 字符串 byte BYTE reverse3

 一、查壳

把文件拖入查壳工具

发现是c++, 由exeinfope可知此程序无壳。

二、静态分析(IDA)

 把文件拖到IDA中

 

接下来寻找 main 函数

 点击图片中的 main ,得到

 反编汇

点击f5 进行反汇编,得到伪代码

进行分析

 分析伪代码

从上往下进行一步步分析一下,进行一下注释

因此目前要搞明白24行那个函数的作用,点进去查看一下

继续点击查看

void *__cdecl sub_411AB0(char *a1, unsigned int a2, int *a3)
{
  int v4; // [esp+D4h] [ebp-38h]
  int v5; // [esp+D4h] [ebp-38h]
  int v6; // [esp+D4h] [ebp-38h]
  int v7; // [esp+D4h] [ebp-38h]
  int i; // [esp+E0h] [ebp-2Ch]
  unsigned int v9; // [esp+ECh] [ebp-20h]
  int v10; // [esp+ECh] [ebp-20h]
  int v11; // [esp+ECh] [ebp-20h]
  void *v12; // [esp+F8h] [ebp-14h]
  char *v13; // [esp+104h] [ebp-8h]

  if ( !a1 || !a2 )
    return 0;
  v9 = a2 / 3;
  if ( (int)(a2 / 3) % 3 )
    ++v9;
  v10 = 4 * v9;
  *a3 = v10;
  v12 = malloc(v10 + 1);
  if ( !v12 )
    return 0;
  j_memset(v12, 0, v10 + 1);
  v13 = a1;
  v11 = a2;
  v4 = 0;
  while ( v11 > 0 )
  {
    byte_41A144[2] = 0;
    byte_41A144[1] = 0;
    byte_41A144[0] = 0;
    for ( i = 0; i < 3 && v11 >= 1; ++i )
    {
      byte_41A144[i] = *v13;
      --v11;
      ++v13;
    }
    if ( !i )
      break;
    switch ( i )
    {
      case 1:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        v5 = v4 + 1;
        *((_BYTE *)v12 + v5) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
        *((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
        *((_BYTE *)v12 + ++v5) = aAbcdefghijklmn[64];
        v4 = v5 + 1;
        break;
      case 2:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        v6 = v4 + 1;
        *((_BYTE *)v12 + v6) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
        *((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
        *((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[64];
        v4 = v6 + 1;
        break;
      case 3:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        v7 = v4 + 1;
        *((_BYTE *)v12 + v7) = aAbcdefghijklmn[((byte_41A144[1] & 0xF0) >> 4) | (16 * (byte_41A144[0] & 3))];
        *((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[((byte_41A144[2] & 0xC0) >> 6) | (4 * (byte_41A144[1] & 0xF))];
        *((_BYTE *)v12 + ++v7) = aAbcdefghijklmn[byte_41A144[2] & 0x3F];
        v4 = v7 + 1;
        break;
    }
  }
  *((_BYTE *)v12 + v4) = 0;
  return v12;
}

点开是这样的

函数参数


a1: 指向输入字符串指针。
a2: 输入字符串的长度。
a3: 指向一个整数的指针,用于存储编码后数据的长度。


局部变量


v4, v5, v6, v7: 用于索引和计数。
i: 循环计数器。
v9: 计算需要多少个Base64字符来存储输入数据。
v10: 计算分配的内存大小(包括一个额外的字节用于存储空字符)。
v11: 用于跟踪剩余的输入数据长度。
v12: 指向分配的内存,用于存储Base64编码的数据。
v13: 输入数据的当前指针。

分析代码


 

 

 

这个函数是一个Base64编码实现,它处理了不同长度的输入数据,并正确地计算了输出数据的长度。

看到16行的"/3"和19行的“*4",这就是base64对字符的二进制编码做的处理,这是定义了v9和v10来存放base64对字符的二进制变化;

结合查到的base64的编码和对伪代码的分析,我们基本明白了大致过程:

将flag输入后经过Base64编码加密,赋值给v4,再复制给Destination,将Destination进行了循环,最后将Destination和str2进行了比较,若相同就是正确的flag,否则就是错误的flag。这一流程说明了Str2中存储的就是加密并且for循环操作后的字符串

逆向思考

Str2-->给Destination减去其索引值-->进行Base解码 

逆向脚本

先的到Str2

先for循环减去for循环中加的数值,再对得到的字符串进行base64解密

import base64
 
Des="e3nifIH9b_C@n@dH"
flag=""
 
for i in range(len(Des)):
    flag+=chr(ord(Des[i])-i)
print(base64.b64decode(flag))

 

得到flag{i_l0ve_you}

三、知识总结

C语言中的标准库函数https://blog.csdn.net/weixin_44793491/article/details/107644666icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_44793491/article/details/107644666

strlen

 在C语言中,strlen 是一个标准库函数,用于计算以 null 结尾的字符串(C 风格字符串)的长度。strlen 函数定义在 <string.h> 头文件中。

size_t strlen(const char *str);
参数
  • str:指向要计算长度的字符串的指针。
返回值
  • 返回值是 size_t 类型,表示字符串的长度,不包括结尾的 null 字符。
功能
  • strlen 函数遍历字符串,直到遇到第一个 null 字符('\0'),然后返回计数的字符数。
示例代码 
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    size_t length = strlen(str);
    printf("Length of '%s' is %zu\n", str, length);
    return 0;
}

得到

Length of 'Hello, World!' is 13
注意事项
  • strlen 传入的字符串必须是以 null 结尾的有效 C 字符串。
  • 如果传入的不是,strlen 可能会读取到内存中的随机位置,直到遇到 null 字符,这可能导致程序崩溃或返回错误的字符串长度。
  • strlen 函数的时间复杂度是 O(n),其中 n 是字符串的长度,因为它需要逐个字符检查直到找到 null 字符。 

strncpy

在C语言中,strncpy 是一个标准库函数,用于将一个字符串复制到另一个字符串中,并且可以指定要复制的最大字符数。strncpy 函数定义在 <string.h> 头文件中。 

char *strncpy(char *dest, const char *src, size_t n);

 

参数

  • dest:指向目标字符串的指针,这是要将数据复制到的位置。
  • src:指向源字符串的指针,这是要从中复制数据的位置。
  • n:指定要复制的最大字符数。

返回值


返回 dest 指向的目标字符串的指针。


功能
  • strncpy 函数从 src 复制最多 n 个字符到 dest。
  • 如果 src 的长度小于 n,则 dest 将用空字符 ('\0') 填充剩余的部分。
  • 如果 src 的长度大于或等于 n,则 dest 不一定会以空字符结尾,这意味着目标字符串可能不会以空字符正确终止。
 示例代码
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[20];
    
    strncpy(dest, src, 13); // 复制整个字符串,包括结尾的空字符
    printf("Copied string: %s\n", dest);

    strncpy(dest, src, 6); // 只复制前6个字符
    printf("Copied partial string: %s\n", dest);
    
    return 0;
}

得到

Copied string: Hello, World!
Copied partial string: Hello, Wor
注意事项

  • strncpy 不保证目标字符串以空字符结尾,如果源字符串长度大于或等于 n,目标字符串可能不会以空字符结尾。
  • 如果你需要确保目标字符串以空字符结尾,你可能需要手动添加一个空字符到 dest[n-1]。
  • 如果源字符串长度小于 n,剩余的字符将被填充为 '\0'。
  • strncpy 可以用于防止缓冲区溢出,但是需要谨慎使用,以确保字符串以空字符结尾。
  • 由于 strncpy 的这些特性,一些开发者和安全专家推荐使用更安全的替代函数,如 strlcpy,它在某些操作系统中可用,并且设计用来防止溢出并确保字符串以空字符结尾。

base64编码 

字符集特征:

Base64编码使用一个包含64个字符的字符集,通常包括大写字母(A-Z)、小写字母(a-z)、数字(0-9)以及两个附加符号(+ 和 / )。还有一个用于填充的等号字符(=)。

本题对应的就是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

base64加密的特征代码:

计算输出长度:Base64编码每3个字节映射到4个字符 

所以计算方法是将输入字节数除以3,然后乘以4。 

v9 = a2 / 3;
if ((int)(a2 / 3) % 3)
    ++v9;
v10 = 4 * v9;

 内存分配:为编码后的字符串分配内存,长度为计算出的长度加1,加1是为了存储字符串结尾的空字符。

v12 = malloc(v10 + 1);

初始化内存:将分配的内存初始化为0。 

j_memset(v12, 0, v10 + 1);

逐字节处理输入数据: 循环处理输入数据,每次最多处理3个字节

while (v11 > 0) {
    // ...
    for (i = 0; i < 3 && v11 >= 1; ++i) {
        byte_41A144[i] = *v13;
        --v11;
        ++v13;
    }
    // ...
}

 Base64编码逻辑:使用了一个查找表 aAbcdefghijklmn,它很可能包含了Base64的64个字符。根据Base64编码规则,将每个字节的位分组,并从查找表中索引对应的字符。

switch (i) {
    case 1:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        // ...
        break;
    case 2:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        // ...
        break;
    case 3:
        *((_BYTE *)v12 + v4) = aAbcdefghijklmn[(int)(unsigned __int8)byte_41A144[0] >> 2];
        // ...
        break;
}

 填充:在处理2个字节的情况时,编码后会有一个Base64字符用作填充。

*((_BYTE *)v12 + ++v6) = aAbcdefghijklmn[64];

结尾空字符:编码结束后,在字符串末尾添加空字符。

*((_BYTE *)v12 + v4) = 0;

 通过这些特征,我们可以推断出这段代码是用于Base64编码的。它遵循了Base64编码的基本规则,包括输入数据的处理方式、查找表的使用、以及填充字符的添加。

 reverse的base64解码脚本

import base64 #导入base64模块用于解密
s1 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' #标准表
s2 = 'qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD' #base64换表
en_text = '5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==' #密文
 
map = str.maketrans(s2, s1) #用str类中的maketrans建立映射,注意第一个参数是需要映射的字符串,第二个参数是映射的目标
map_text = en_text.translate(map) #映射实现替换密文,替换前是base64换表加密,替换后则是base64标准表加密
print(map_text) #可以先看看标准表加密的原base64密文
print(base64.b64decode(map_text)) #直接使用提供的base64解密函数解密

 

 

 

标签:BUUCTF,41A144,v12,int,字符串,byte,BYTE,reverse3
From: https://blog.csdn.net/Co_xy/article/details/144608597

相关文章

  • BUUCTF nextGen1 (小白能看懂)
    题目中的提示所flag就藏在服务器的/flag.txt中,但是如果直接访问并没有得到flag,如下图所示做web题我喜欢先查看源码看看有没有什么超链接点进去看看,其它超链接点进去没有发现有用的信息,可以看到这下面有一个超链接,最后一个超链接里面发现js代码查看一下意思functionmyFunc(......
  • BUUCTF Pwn jarvisoj_level2_x64 题解
    1.下载checksec64位用IDA64打开SHIFT+F12查找字符串找到了binsh函数里面也有system进主函数看看看到了栈溢出漏洞这是64位程序所以构造ROP链时要用rdi传参+用ret栈平衡找到这两个的地址:构造exp:运行得到flag  flag{4b1340f5-06be-4377-9630-fd2c77f016......
  • BUUCTF_MISC题解析(7)
    7.wireshark下载文件发现里面是一个pcap格式的文件。而pcap格式就是网络分析工具保存的网络数据包,是捕获的从网卡发送或者接收的每一个数据包的离线网络流量。 在wireshark官网上下载wireshark,wireshark是网络封包分析工具。将文件用wireshark打开,发现有三个部分,上半部分绿......
  • BUUCTF_MISC题解析(6,8)
    6.乌镇峰会种图把打开的图片放进010editor,拉到最末尾就可以发现flag 8.N种方法解决打开文件是KEY.exe点击打不开,运行不了(exe文件是二进制文件),所以把他拉到010editor打开,data:image/jpg;base64,iVBORw0KGgo......gg==发现是base编码的形式,开头的提示说明是jpg格式的图片,......
  • BUUCTF_MISC题解析(3,4)
    3.你竟然赶我走搜索010editor官网,点第一个页面,下载010editor(十六进制编译器)(黄色图标),直接010editor打开(或者使用stegSolve)一般情况用ctrl+f进入字符串搜索查看是否有插入的flag信息,就可以在文件尾看到flag是flag{stego_is_s0_bor1ing} 4.二维码扫码识别二维码,发现隐......
  • BUUCTF蜘蛛侠呀
    解压后发现是流量包,好多icmp包发现icmp包尾部有$$STRAT打头16进制的字符串,好多重复得。我们只需要提取尾部这些字符串是当icmp的type=0时上图标识为褐色的字符串,还需要把16进制的字符串转为对应的字符串(bytes类型)并去重。使用python脚本importpysharkimportbinascii......
  • 【CTF Web】BUUCTF SQLi-LABS Page-1(Basic Challenges) Less-12 Writeup(SQL注入+POST
    sqli-labs1点击启动靶机。SQLi-LABSPage-1(BasicChallenges)解法随便提交一些数据。审查元素。<formaction=""name="form1"method="post"> <divstyle="margin-top:15px;height:30px;">Username:&nbsp;&nbsp;&......
  • 【CTF Web】BUUCTF SQLi-LABS Page-1(Basic Challenges) Less-6 Writeup(SQL注入+GET请
    sqli-labs1点击启动靶机。SQLi-LABSPage-1(BasicChallenges)原理双注入模板:selectcount(*),concat(([payload]),floor(rand(0)*2))asafrom[table_name]groupbya解法发送GET请求,id作为参数。http://b3f804a6-9ba6-418d-ac25-bf8d48589b62.node5.......
  • XXE之读取任意文件 BUUCTF [PHP]XXE
    开启BUUCTF靶场,打开链接:很明显是个phpinfo.php文件直接CtflF搜索flag,发现还真有,尝试输入flag看看什么情况?flag{cce98ec0-f1e6-416f-86d7-9b174202e678}呃呃,还真是flag,不过还是换种思路来做吧看到上面有个github的链接,点进去看看发现是一段例子和介绍,将其复......
  • [BUUCTF 2018]Online Tool 1
    <?phpif(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){$_SERVER['REMOTE_ADDR']=$_SERVER['HTTP_X_FORWARDED_FOR'];}if(!isset($_GET['host'])){highlight_file(__FILE__);}else{$host=$_GET['......