首页
社区
课程
招聘
[原创]KCTF2023 第六题 至暗时刻
发表于: 2023-9-14 11:23 9659

[原创]KCTF2023 第六题 至暗时刻

2023-9-14 11:23
9659

代码中有很多syscall,win11调试进不去,需要布置win10虚拟机调试,才能看到函数名

创建的第一个线程,每次调用RtlFillMemory拷贝1字节,跟踪发现拷贝的就是 unk_140008050 中的数据,而且看着像jmp指令:

用IDA加载能识别为代码,但是有很多错误。需要x64dbg调试shellcode。
先内存断,再执行断。shellcode运行后会将所有17替换成00,重新拿到shellcode,IDA F5就能完美识别

然后就是反复调试,发现字符串分为3块:
3201382652D139C0E22132DF1BC2212EA0991650A229B36436823D0B13D51E6 //前缀,3位一个16进制数
input //必须是3的倍数,后续分析长度必须是180
677116575313142309154604431859253431473963507533496829080645035455771774602058076430276921790210013736267644383505517280 //后缀 2位一个10进制数

核心函数是2063B,要求input每3位,是一个十六进制
比如 input[0]="112",0x112=274,十位*9+个位=67,要跟后缀[0]相等
十位和个位就确定了。

同时十位和个位要作为下标,充当数独的坐标。百位就是数独的内容。
数独一共是9*9个格子,其中前缀是21个数,input是60个数。所以先转换已有的21个数,更新到棋盘

再求解出答案:

编程反算数独下标,

.text:0000000140001324 FF 15 2E 4D 00 00                          call    cs:IsDebuggerPresent
.text:000000014000132A 85 C0                                      test    eax, eax
.text:000000014000132C 74 05                                      jz      short loc_140001333
.text:0000000140001324 FF 15 2E 4D 00 00                          call    cs:IsDebuggerPresent
.text:000000014000132A 85 C0                                      test    eax, eax
.text:000000014000132C 74 05                                      jz      short loc_140001333
.text:0000000140001324 FF 15 2E 4D 00 00                          call    cs:IsDebuggerPresent
.text:000000014000132A | 31C0                     | xor eax,eax                             |
.text:000000014000132C | EB 05                    | jmp blackclient_.140001333              |
.text:000000014000132E | E8 65FFFFFF              | call blackclient_.140001298             |
.text:0000000140001324 FF 15 2E 4D 00 00                          call    cs:IsDebuggerPresent
.text:000000014000132A | 31C0                     | xor eax,eax                             |
.text:000000014000132C | EB 05                    | jmp blackclient_.140001333              |
.text:000000014000132E | E8 65FFFFFF              | call blackclient_.140001298             |
.text:0000000140001484 FF 15 DE 4B 00 00                          call    cs:CheckRemoteDebuggerPresent
.text:000000014000148A 83 7D 38 00                                cmp     [rbp+pbDebuggerPresent], 0
.text:000000014000148E 0F 84 95 00 00 00                          jz      loc_140001529
.text:0000000140001494 B9 08 00 00 00                             mov     ecx, 8          ; Size
.text:0000000140001484 FF 15 DE 4B 00 00                          call    cs:CheckRemoteDebuggerPresent
.text:000000014000148A 83 7D 38 00                                cmp     [rbp+pbDebuggerPresent], 0
.text:000000014000148E 0F 84 95 00 00 00                          jz      loc_140001529
.text:0000000140001494 B9 08 00 00 00                             mov     ecx, 8          ; Size
  fun_scanf((__int64)"%s", input_1, v64);
  fun_decode(v15, v52, (__int64)"*s>0?", 5);    // kctf
  sub_1400026AC(&Src, v16, v52, v17, qword_140009A80);// kctf拼接到字符串前面
  sub_140002BBA((__int64)v19, (__int64)&Source, 0i64, (__int64)&v69, Size);// NtAllocateVirtualMemory
  sub_140002DA9((__int64)v19);                  // NtWriteVirtualMemory
  fun_decode(v20, v58, (__int64)"!?>d*", 5);    // kernel32.dll
  fun_decode(v22, v55, (__int64)"?x)da", v21);  // RtlFillMemory(地址,大小,值)
( (unsigned int)sub_140003529((__int64)&hThread) )// NtCreateThreadEx
  strncpy((char *)&Str1, Source + 67, 3ui64);
  if ( !strcmp((const char *)&Str1, "110") )    // 此时Str1=="110"
  {
    v43 = &unk_140006590;
  }
  else
  {
    if ( strcmp((const char *)&Str1, "120") )   // 不等于120,就退出
      ExitProcess(0);
    v43 = &unk_140006598;
  }
  fun_decode(&Dest, 3, (__int64)v43, 3);
  fun_printf((__int64)&unk_14000659C, &Dest);   // 这里肯定就是打印成功了
  fun_scanf((__int64)"%s", input_1, v64);
  fun_decode(v15, v52, (__int64)"*s>0?", 5);    // kctf
  sub_1400026AC(&Src, v16, v52, v17, qword_140009A80);// kctf拼接到字符串前面
  sub_140002BBA((__int64)v19, (__int64)&Source, 0i64, (__int64)&v69, Size);// NtAllocateVirtualMemory
  sub_140002DA9((__int64)v19);                  // NtWriteVirtualMemory
  fun_decode(v20, v58, (__int64)"!?>d*", 5);    // kernel32.dll
  fun_decode(v22, v55, (__int64)"?x)da", v21);  // RtlFillMemory(地址,大小,值)
( (unsigned int)sub_140003529((__int64)&hThread) )// NtCreateThreadEx
  strncpy((char *)&Str1, Source + 67, 3ui64);
  if ( !strcmp((const char *)&Str1, "110") )    // 此时Str1=="110"
  {
    v43 = &unk_140006590;
  }
  else
  {
    if ( strcmp((const char *)&Str1, "120") )   // 不等于120,就退出
      ExitProcess(0);
    v43 = &unk_140006598;
  }
  fun_decode(&Dest, 3, (__int64)v43, 3);
  fun_printf((__int64)&unk_14000659C, &Dest);   // 这里肯定就是打印成功了
__int64 sub_20217()
{
  __int64 (__fastcall *CreateToolhelp32Snapshot)(signed __int64, _QWORD); // rbx
  __int64 (__fastcall *Process32First)(__int64, int *); // r13
  void (__fastcall *CloseHandle)(__int64); // r15
  __int64 (*GetCurrentProcessId)(void); // r12
  __int64 process; // rdi
  bool v5; // si
  __int64 handle; // rax
  __int64 v7; // r14
  int v9; // eax
  __int64 (__fastcall *Process32Next_1)(__int64, int *); // rbx
  __int64 (__fastcall *OpenProcess_1)(signed __int64, _QWORD); // r13
  __int64 address; // rbx
  int v13; // eax
  int *v14; // rdx
  _BYTE *v15; // rbx
  int *lpBuffer; // [rsp+48h] [rbp-2B0h]
  int v17; // [rsp+58h] [rbp-2A0h]
  __int64 v18; // [rsp+60h] [rbp-298h]
  int v19; // [rsp+68h] [rbp-290h]
  int v20; // [rsp+80h] [rbp-278h]
  int v21; // [rsp+88h] [rbp-270h]
  __int64 Process32Next; // [rsp+300h] [rbp+8h]
  __int64 OpenProcess; // [rsp+308h] [rbp+10h]
  __int64 (__fastcall *VirtualQueryEx)(__int64, __int64, int **, signed __int64); // [rsp+310h] [rbp+18h]
 
  CreateToolhelp32Snapshot = (__int64 (__fastcall *)(signed __int64, _QWORD))sub_20563(0xF88DDF46);
  OpenProcess = sub_20563(0xFD0B55A7);
  VirtualQueryEx = (__int64 (__fastcall *)(__int64, __int64, int **, signed __int64))sub_20563(0x242E6FF);
  Process32First = (__int64 (__fastcall *)(__int64, int *))sub_20563(0x3F347695);
  Process32Next = sub_20563(-1813961927);
  CloseHandle = (void (__fastcall *)(__int64))sub_20563(0x1CA655F1);
  GetCurrentProcessId = (__int64 (*)(void))sub_20563(55981281);
  process = 0i64;
  v20 = 0x238;
  v5 = 0;
  handle = CreateToolhelp32Snapshot(2i64, 0i64);
  v7 = handle;
  if ( handle == -1 )
    return 0xFFFFFFFFi64;
  v9 = Process32First(handle, &v20);
  Process32Next_1 = (__int64 (__fastcall *)(__int64, int *))Process32Next;
  OpenProcess_1 = (__int64 (__fastcall *)(signed __int64, _QWORD))OpenProcess;
  while ( v9 )
  {
    if ( v21 == (unsigned int)GetCurrentProcessId() )
    {
      process = OpenProcess_1(0x2000000i64, 0i64);
      if ( process )
      {
        address = 0i64;
        while ( 1 )
        {
          do
          {
            if ( !VirtualQueryEx(process, address, &lpBuffer, 48i64) )
            {
              Process32Next_1 = (__int64 (__fastcall *)(__int64, int *))Process32Next;
              OpenProcess_1 = (__int64 (__fastcall *)(signed __int64, _QWORD))OpenProcess;
              goto LABEL_20;
            }
            address = (__int64)lpBuffer + v18;
          }
          while ( v19 != 4096 || v17 != 64 );
          v13 = GetCurrentProcessId();
          v14 = lpBuffer;
          if ( v21 == v13 )
            v5 = sub_2062F(*lpBuffer);
          if ( v5 )
            break;
          *(_BYTE *)v14 = 'm';                  // 第一层判断,kctf头
          *((_BYTE *)v14 + 1) = 'j';
          *((_BYTE *)v14 + 2) = ')';
          *((_BYTE *)v14 + 3) = 0;
          *((_BYTE *)v14 + 67) = '1';
          *((_BYTE *)v14 + 68) = '2';
          *((_BYTE *)v14 + 69) = '0';
        }
        v15 = v14 + 1;
        if ( sub_20AA3((__int64)(v14 + 1)) )    // 所有判断,都在这里呗 传入kctf后面的字符串
        {
          *(v15 - 4) = 'i';                     // 正确答案!!!!!!
          *(v15 - 3) = 'o';
          *(v15 - 2) = ' ';
          *(v15 - 1) = 0;
          v15[63] = '1';
          v15[64] = '1';
        }
        else
        {
          *(v15 - 4) = 'm';
          *(v15 - 3) = 'j';
          *(v15 - 2) = ')';
          *(v15 - 1) = 0;
          v15[63] = '1';
          v15[64] = '2';
        }
        v15[65] = '0';
        break;
      }
    }
LABEL_20:
    v9 = Process32Next_1(v7, &v20);
  }
  CloseHandle(v7);
  return ((__int64 (__fastcall *)(__int64))CloseHandle)(process);
}
__int64 sub_20217()
{
  __int64 (__fastcall *CreateToolhelp32Snapshot)(signed __int64, _QWORD); // rbx
  __int64 (__fastcall *Process32First)(__int64, int *); // r13
  void (__fastcall *CloseHandle)(__int64); // r15
  __int64 (*GetCurrentProcessId)(void); // r12
  __int64 process; // rdi
  bool v5; // si
  __int64 handle; // rax
  __int64 v7; // r14
  int v9; // eax
  __int64 (__fastcall *Process32Next_1)(__int64, int *); // rbx
  __int64 (__fastcall *OpenProcess_1)(signed __int64, _QWORD); // r13
  __int64 address; // rbx
  int v13; // eax
  int *v14; // rdx
  _BYTE *v15; // rbx
  int *lpBuffer; // [rsp+48h] [rbp-2B0h]
  int v17; // [rsp+58h] [rbp-2A0h]
  __int64 v18; // [rsp+60h] [rbp-298h]
  int v19; // [rsp+68h] [rbp-290h]
  int v20; // [rsp+80h] [rbp-278h]
  int v21; // [rsp+88h] [rbp-270h]
  __int64 Process32Next; // [rsp+300h] [rbp+8h]
  __int64 OpenProcess; // [rsp+308h] [rbp+10h]
  __int64 (__fastcall *VirtualQueryEx)(__int64, __int64, int **, signed __int64); // [rsp+310h] [rbp+18h]
 
  CreateToolhelp32Snapshot = (__int64 (__fastcall *)(signed __int64, _QWORD))sub_20563(0xF88DDF46);
  OpenProcess = sub_20563(0xFD0B55A7);
  VirtualQueryEx = (__int64 (__fastcall *)(__int64, __int64, int **, signed __int64))sub_20563(0x242E6FF);
  Process32First = (__int64 (__fastcall *)(__int64, int *))sub_20563(0x3F347695);
  Process32Next = sub_20563(-1813961927);
  CloseHandle = (void (__fastcall *)(__int64))sub_20563(0x1CA655F1);
  GetCurrentProcessId = (__int64 (*)(void))sub_20563(55981281);
  process = 0i64;
  v20 = 0x238;
  v5 = 0;
  handle = CreateToolhelp32Snapshot(2i64, 0i64);
  v7 = handle;
  if ( handle == -1 )
    return 0xFFFFFFFFi64;
  v9 = Process32First(handle, &v20);
  Process32Next_1 = (__int64 (__fastcall *)(__int64, int *))Process32Next;
  OpenProcess_1 = (__int64 (__fastcall *)(signed __int64, _QWORD))OpenProcess;
  while ( v9 )
  {
    if ( v21 == (unsigned int)GetCurrentProcessId() )
    {
      process = OpenProcess_1(0x2000000i64, 0i64);
      if ( process )
      {
        address = 0i64;
        while ( 1 )
        {
          do
          {
            if ( !VirtualQueryEx(process, address, &lpBuffer, 48i64) )
            {
              Process32Next_1 = (__int64 (__fastcall *)(__int64, int *))Process32Next;
              OpenProcess_1 = (__int64 (__fastcall *)(signed __int64, _QWORD))OpenProcess;
              goto LABEL_20;
            }
            address = (__int64)lpBuffer + v18;
          }
          while ( v19 != 4096 || v17 != 64 );
          v13 = GetCurrentProcessId();
          v14 = lpBuffer;
          if ( v21 == v13 )
            v5 = sub_2062F(*lpBuffer);
          if ( v5 )
            break;
          *(_BYTE *)v14 = 'm';                  // 第一层判断,kctf头
          *((_BYTE *)v14 + 1) = 'j';
          *((_BYTE *)v14 + 2) = ')';
          *((_BYTE *)v14 + 3) = 0;

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//