首页
社区
课程
招聘
[原创] KCTF 2023 第六题 wp - 98k
发表于: 2023-9-14 00:35 9085

[原创] KCTF 2023 第六题 wp - 98k

2023-9-14 00:35
9085

main 之前有两个 TlsCallback 用于反调试,直接 patch 掉;

进入 main ,新开一个线程,执行函数 sub_140001630

sub_140001630 就是主逻辑,字符串都加密了,异或解密之后就能看出来逻辑:

常规流程,提示后输入,之后和 "kctf" 以及两个 main 之前初始化的全局变量字符串拼接 "kctf" + str1 + input + str2 ,之后写入到分配的一段内存上,再调用 write_memory 函数向 +500 的位置写入 shellcode ,再用 NtQueueApcThread 执行这段代码。 write_memory 中还有个反调试,去掉就行(上面是已经去掉的)。

write_memory 中可以看到, shellcode 的位置在 0x140008050 ,直接跳转过去,第一条 call 是花指令,跳转到当前地址 +4 的位置,处理后如下:

这一小段循环会将后面指令中的所有 0x17 全部改成 0 ,写个脚本去掉就行,在 0x140008073 处生成函数 F5 :

check_header 函数就检测头部的 "kctf" ,通过这种方式找到分配的这段内存,之后进入 flag 的判断(数独的判断)

进入 check_sudoku 就很明显的能看到,完全就是数独的判断逻辑。最后就只剩下一个函数 get_value ,这里会得到输入的格式的判断。 get_value 里的逻辑比较乱,简单整理一下函数行为:每次读取输入的 3 个字节,必须是数字或者大写的 A-F ,之后这三个字符计算得到 16 进制的数值,10进制表示的个位、十位、百位分别是数独中的 x, y, sudoku[y][x] 。当取到的 y 和 x 与传入的参数相符合时,就会结束循环。如果当前取到的输入的下标不超过 63 (第 21 组内,即原 str1 的范围内),则直接返回;否则会取后 120 字节进行判断,其中找到与 9 * y + x 相等的 2 字节对应的 10 进制数,并且这个下标和要和前一部分的每 3 字节的下标相差 21 (即跳过前面的 21 组),最后还会判断总长度是 243 + 120 保证没有多余字节。

所以前面的 63 字节是给出数独中已有的值,后 120 字节指定了输入的数独格子的顺序。直接套用 z3 例子求解:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  _QWORD *v3; // rax
  _Thrd_t ThrdAddr; // [rsp+30h] [rbp-28h] BYREF
  _Thrd_t v6; // [rsp+40h] [rbp-18h] BYREF
 
  v3 = operator new(8ui64);
  *v3 = sub_140001630;
  ThrdAddr._Hnd = (void *)beginthreadex(0i64, 0, (_beginthreadex_proc_type)StartAddress, v3, 0, &ThrdAddr._Id);
  if ( !ThrdAddr._Hnd )
  {
    ThrdAddr._Id = 0;
    std::_Throw_Cpp_error(6);
  }
  if ( !ThrdAddr._Id )
    std::_Throw_Cpp_error(1);
  if ( ThrdAddr._Id == Thrd_id() )
    std::_Throw_Cpp_error(5);
  v6 = ThrdAddr;
  if ( Thrd_join(&v6, 0i64) )
    std::_Throw_Cpp_error(2);
  return 0;
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
  _QWORD *v3; // rax
  _Thrd_t ThrdAddr; // [rsp+30h] [rbp-28h] BYREF
  _Thrd_t v6; // [rsp+40h] [rbp-18h] BYREF
 
  v3 = operator new(8ui64);
  *v3 = sub_140001630;
  ThrdAddr._Hnd = (void *)beginthreadex(0i64, 0, (_beginthreadex_proc_type)StartAddress, v3, 0, &ThrdAddr._Id);
  if ( !ThrdAddr._Hnd )
  {
    ThrdAddr._Id = 0;
    std::_Throw_Cpp_error(6);
  }
  if ( !ThrdAddr._Id )
    std::_Throw_Cpp_error(1);
  if ( ThrdAddr._Id == Thrd_id() )
    std::_Throw_Cpp_error(5);
  v6 = ThrdAddr;
  if ( Thrd_join(&v6, 0i64) )
    std::_Throw_Cpp_error(2);
  return 0;
}
__int64 sub_140001630()
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
 
  std::string::ctor(&input_string, empty);
  std::string::ctor(&Format, s);                // 'Please enter your key:'
  std::string::ctor(&str_kernel32_dll, aJzlOmJnms);// kernel32.dll
  std::string::ctor(&str_RtlFillMemory, aM);
  std::string::ctor(&str_kctf, aAJv);           // kctf
  std::string::append(&str_RtlFillMemory, aD_0);// RtlFillMemory
  std::string::ctor(&Block, "7PK:");
  v0 = (char *)&Format;
  if ( Format.cap >= 0x10 )
    v0 = Format.data.lstr;
  vigenere_decrypt(v0, Format.size, "&x+^x", 5);
  v1 = (char *)&Format;
  if ( Format.cap >= 0x10 )
    v1 = Format.data.lstr;
  printf(v1);
  v2 = input_string.size;
  // set input length to 500
  if ( input_string.size < 500 )
  {
    // ...
  }
  else
  {
    // ...
  }
  v7 = (char *)&input_string;
  if ( input_string.cap >= 0x10 )
    v7 = input_string.data.lstr;
  scanf("%s", v7);
  v8 = (char *)&input_string;
  if ( input_string.cap >= 0x10 )
    v8 = input_string.data.lstr;
  v9 = (char *)&str1;
  std::string::append(&str1, v8);
  v10 = (char *)&str2;
  if ( str2.cap >= 0x10 )
    v10 = str2.data.lstr;
  v11 = str2.size;
  v12 = str1.size;
  str1 += str2; // ...
  v15 = (char *)&str_kctf;
  if ( str_kctf.cap >= 0x10 )
    v15 = str_kctf.data.lstr;
  vigenere_decrypt(v15, str_kctf.size, "*s>0?", 5);
  str1 = str_kctf + str1; // ...
  ProcessHandle = GetCurrentProcess();
  RegionSize = 5500i64;
  NtAllocateVirtualMemory(
    ProcessHandle,
    (PVOID *)&alloced,
    0i64,
    &RegionSize,
    MEM_RESERVE|MEM_COMMIT,
    PAGE_EXECUTE_READWRITE);
  if ( str1.cap >= 0x10 )
    v9 = str1.data.lstr;
  NtWriteVirtualMemory(ProcessHandle, alloced, v9, str1.size, NumberOfBytesWritten);
  v20 = (char *)&str_kernel32_dll;
  if ( str_kernel32_dll.cap >= 0x10 )
    v20 = str_kernel32_dll.data.lstr;
  vigenere_decrypt(v20, str_kernel32_dll.size, "!?>d*", 5);
  v22 = (char *)&str_RtlFillMemory;
  if ( str_RtlFillMemory.cap >= 0x10 )
    v22 = str_RtlFillMemory.data.lstr;
  vigenere_decrypt(v22, str_RtlFillMemory.size, "?x)da", v21);
  v23 = (char *)&str_RtlFillMemory;
  if ( str_RtlFillMemory.cap >= 0x10 )
    v23 = str_RtlFillMemory.data.lstr;
  v24 = (char *)&str_kernel32_dll;
  if ( str_kernel32_dll.cap >= 0x10 )
    v24 = str_kernel32_dll.data.lstr;
  kernel32_dll = GetModuleHandleA(v24);
  RtlFillMemory = (void (__fastcall *)(void *, size_t, int))GetProcAddress(kernel32_dll, v23);
  if ( !RtlFillMemory || write_memory(ProcessHandle, alloced + 500) )
  {
    // string dtor
    return 1i64;
  }
  if ( NtCreateThreadEx(
         &hThread,
         0x1FFFFFu,
         0i64,
         ProcessHandle,
         (LPTHREAD_START_ROUTINE)ExitThread,
         0i64,
         1u,
         0i64,
         0i64,
         0i64,
         0i64) )
  {
    // string dtor
    return 1;
  }
  NtQueueApcThread(hThread, (PIO_APC_ROUTINE)(alloced + 500), 0i64, 0i64, 0i64);
  ResumeThread(hThread);
  NtWaitForSingleObject(hThread, 0, 0i64);
  CloseHandle(hThread);
  *(_DWORD *)Str1 = 0;
  *(_DWORD *)Destination = 0;
  strncpy(Destination, (const char *)alloced, 3ui64);
  strncpy(Str1, (const char *)alloced + 67, 3ui64);
  if ( !strcmp(Str1, "110") )
  {
    v40 = (char *)&unk_140006590;
  }
  else
  {
    if ( strcmp(Str1, "120") )
      ExitProcess(0);
    v40 = (char *)&byte_140006598;
  }
  vigenere_decrypt(Destination, 3, v40, 3);
  printf("\n%s", Destination);
  // string dtor
  return 0i64;
}
 
int __fastcall write_memory(HANDLE ProcessHandle, unsigned __int8 *ptr)
{
  int v4; // edi
  unsigned __int8 *i; // rsi
 
  GetCurrentProcess();
  if ( !NtCreateThreadEx(
          &Handle,
          0x1FFFFFu,
          0i64,
          ProcessHandle,
          (LPTHREAD_START_ROUTINE)ExitThread,
          0i64,
          1u,
          0i64,
          0i64,
          0i64,
          0i64) )
  {
    v4 = 0;
    for ( i = unk_140008050; !NtQueueApcThread(Handle, (PIO_APC_ROUTINE)RtlFillMemory, &ptr[v4], 1i64, *i); ++i )
    {
      if ( (unsigned int)++v4 >= 0x92B )
      {
        ResumeThread(Handle);
        NtWaitForSingleObject(Handle, 0, 0i64);
        CloseHandle(Handle);
        return 0;
      }
    }
    TerminateThread(Handle, 0);
    CloseHandle(Handle);
  }
  return 1;
}
__int64 sub_140001630()
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
 
  std::string::ctor(&input_string, empty);
  std::string::ctor(&Format, s);                // 'Please enter your key:'
  std::string::ctor(&str_kernel32_dll, aJzlOmJnms);// kernel32.dll
  std::string::ctor(&str_RtlFillMemory, aM);
  std::string::ctor(&str_kctf, aAJv);           // kctf
  std::string::append(&str_RtlFillMemory, aD_0);// RtlFillMemory
  std::string::ctor(&Block, "7PK:");
  v0 = (char *)&Format;
  if ( Format.cap >= 0x10 )
    v0 = Format.data.lstr;
  vigenere_decrypt(v0, Format.size, "&x+^x", 5);
  v1 = (char *)&Format;
  if ( Format.cap >= 0x10 )
    v1 = Format.data.lstr;
  printf(v1);
  v2 = input_string.size;
  // set input length to 500
  if ( input_string.size < 500 )
  {
    // ...
  }
  else
  {
    // ...
  }
  v7 = (char *)&input_string;
  if ( input_string.cap >= 0x10 )
    v7 = input_string.data.lstr;
  scanf("%s", v7);
  v8 = (char *)&input_string;
  if ( input_string.cap >= 0x10 )
    v8 = input_string.data.lstr;
  v9 = (char *)&str1;
  std::string::append(&str1, v8);
  v10 = (char *)&str2;
  if ( str2.cap >= 0x10 )
    v10 = str2.data.lstr;
  v11 = str2.size;
  v12 = str1.size;
  str1 += str2; // ...
  v15 = (char *)&str_kctf;
  if ( str_kctf.cap >= 0x10 )
    v15 = str_kctf.data.lstr;
  vigenere_decrypt(v15, str_kctf.size, "*s>0?", 5);
  str1 = str_kctf + str1; // ...
  ProcessHandle = GetCurrentProcess();
  RegionSize = 5500i64;
  NtAllocateVirtualMemory(
    ProcessHandle,
    (PVOID *)&alloced,
    0i64,
    &RegionSize,
    MEM_RESERVE|MEM_COMMIT,
    PAGE_EXECUTE_READWRITE);
  if ( str1.cap >= 0x10 )
    v9 = str1.data.lstr;
  NtWriteVirtualMemory(ProcessHandle, alloced, v9, str1.size, NumberOfBytesWritten);
  v20 = (char *)&str_kernel32_dll;
  if ( str_kernel32_dll.cap >= 0x10 )
    v20 = str_kernel32_dll.data.lstr;
  vigenere_decrypt(v20, str_kernel32_dll.size, "!?>d*", 5);
  v22 = (char *)&str_RtlFillMemory;
  if ( str_RtlFillMemory.cap >= 0x10 )
    v22 = str_RtlFillMemory.data.lstr;
  vigenere_decrypt(v22, str_RtlFillMemory.size, "?x)da", v21);
  v23 = (char *)&str_RtlFillMemory;
  if ( str_RtlFillMemory.cap >= 0x10 )
    v23 = str_RtlFillMemory.data.lstr;
  v24 = (char *)&str_kernel32_dll;
  if ( str_kernel32_dll.cap >= 0x10 )
    v24 = str_kernel32_dll.data.lstr;
  kernel32_dll = GetModuleHandleA(v24);
  RtlFillMemory = (void (__fastcall *)(void *, size_t, int))GetProcAddress(kernel32_dll, v23);
  if ( !RtlFillMemory || write_memory(ProcessHandle, alloced + 500) )
  {
    // string dtor
    return 1i64;
  }
  if ( NtCreateThreadEx(
         &hThread,
         0x1FFFFFu,
         0i64,
         ProcessHandle,
         (LPTHREAD_START_ROUTINE)ExitThread,
         0i64,
         1u,
         0i64,
         0i64,
         0i64,
         0i64) )
  {
    // string dtor
    return 1;
  }
  NtQueueApcThread(hThread, (PIO_APC_ROUTINE)(alloced + 500), 0i64, 0i64, 0i64);
  ResumeThread(hThread);
  NtWaitForSingleObject(hThread, 0, 0i64);
  CloseHandle(hThread);
  *(_DWORD *)Str1 = 0;
  *(_DWORD *)Destination = 0;
  strncpy(Destination, (const char *)alloced, 3ui64);
  strncpy(Str1, (const char *)alloced + 67, 3ui64);
  if ( !strcmp(Str1, "110") )
  {
    v40 = (char *)&unk_140006590;
  }
  else
  {
    if ( strcmp(Str1, "120") )
      ExitProcess(0);
    v40 = (char *)&byte_140006598;
  }
  vigenere_decrypt(Destination, 3, v40, 3);
  printf("\n%s", Destination);
  // string dtor
  return 0i64;
}
 
int __fastcall write_memory(HANDLE ProcessHandle, unsigned __int8 *ptr)
{
  int v4; // edi
  unsigned __int8 *i; // rsi
 
  GetCurrentProcess();
  if ( !NtCreateThreadEx(
          &Handle,
          0x1FFFFFu,
          0i64,
          ProcessHandle,
          (LPTHREAD_START_ROUTINE)ExitThread,
          0i64,
          1u,
          0i64,
          0i64,
          0i64,
          0i64) )
  {
    v4 = 0;
    for ( i = unk_140008050; !NtQueueApcThread(Handle, (PIO_APC_ROUTINE)RtlFillMemory, &ptr[v4], 1i64, *i); ++i )
    {
      if ( (unsigned int)++v4 >= 0x92B )
      {
        ResumeThread(Handle);
        NtWaitForSingleObject(Handle, 0, 0i64);
        CloseHandle(Handle);
        return 0;
      }
    }
    TerminateThread(Handle, 0);
    CloseHandle(Handle);
  }
  return 1;
}
.data:0000000140008054                 inc     eax
.data:0000000140008056                 pop     rdi
.data:0000000140008057                 mov     ecx, 1010806h
.data:000000014000805C                 xor     ecx, 1010101h   ; 0x907
.data:0000000140008062                 add     rdi, 1Eh        ; 0x140008073
.data:0000000140008066                 xor     esi, esi
.data:0000000140008068                 cld
.data:0000000140008069
.data:0000000140008069 loc_140008069:                          ; CODE XREF: .data:0000000140008071↓j
.data:0000000140008069                 mov     al, [rdi]
.data:000000014000806B                 cmp     al, 17h
.data:000000014000806D                 cmovz   eax, esi
.data:0000000140008070                 stosb
.data:0000000140008071                 loop    loc_140008069
.data:0000000140008054                 inc     eax
.data:0000000140008056                 pop     rdi
.data:0000000140008057                 mov     ecx, 1010806h
.data:000000014000805C                 xor     ecx, 1010101h   ; 0x907
.data:0000000140008062                 add     rdi, 1Eh        ; 0x140008073
.data:0000000140008066                 xor     esi, esi
.data:0000000140008068                 cld
.data:0000000140008069
.data:0000000140008069 loc_140008069:                          ; CODE XREF: .data:0000000140008071↓j
.data:0000000140008069                 mov     al, [rdi]
.data:000000014000806B                 cmp     al, 17h
.data:000000014000806D                 cmovz   eax, esi
.data:0000000140008070                 stosb
.data:0000000140008071                 loop    loc_140008069
void __fastcall check()
{
  HANDLE (__fastcall *CreateToolhelp32Snapshot)(DWORD, DWORD); // rbx
  BOOL (__stdcall *Process32First)(HANDLE, LPPROCESSENTRY32); // r13
  BOOL (__stdcall *CloseHandle)(HANDLE); // r15
  DWORD (__stdcall *GetCurrentProcessId)(); // r12
  HANDLE v4; // rdi
  bool v5; // si
  HANDLE v6; // rax
  void *v7; // r14
  BOOL i; // eax
  char *v11; // rbx
  DWORD v12; // eax
  _BYTE *v13; // rdx
  _BYTE *v14; // rbx
  struct _MEMORY_BASIC_INFORMATION Buffer; // [rsp+48h] [rbp-2B0h] BYREF
  PROCESSENTRY32 v16[2]; // [rsp+80h] [rbp-278h] BYREF
  BOOL (__stdcall *Process32Next)(HANDLE, LPPROCESSENTRY32); // [rsp+300h] [rbp+8h] MAPDST
  HANDLE (__stdcall *OpenProcess)(DWORD, BOOL, DWORD); // [rsp+308h] [rbp+10h] MAPDST
  SIZE_T (__stdcall *VirtualQueryEx)(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); // [rsp+310h] [rbp+18h]
 
  CreateToolhelp32Snapshot = (HANDLE (__fastcall *)(DWORD, DWORD))find_proc(0xF88DDF46);
  OpenProcess = (HANDLE (__stdcall *)(DWORD, BOOL, DWORD))find_proc(0xFD0B55A7);
  VirtualQueryEx = (SIZE_T (__stdcall *)(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T))find_proc(0x242E6FF);
  Process32First = (BOOL (__stdcall *)(HANDLE, LPPROCESSENTRY32))find_proc(0x3F347695);
  Process32Next = (BOOL (__stdcall *)(HANDLE, LPPROCESSENTRY32))find_proc(0x93E12339);
  CloseHandle = (BOOL (__stdcall *)(HANDLE))find_proc(0x1CA655F1);
  GetCurrentProcessId = (DWORD (__stdcall *)())find_proc(0x35634E1);
  v4 = 0i64;
  v16[0].dwSize = 568;
  v5 = 0;
  v6 = CreateToolhelp32Snapshot(2i64, 0i64);
  v7 = v6;
  if ( v6 != (HANDLE)-1i64 )
  {
    for ( i = Process32First(v6, v16); i; i = Process32Next(v7, v16) )
    {
      if ( v16[0].th32ProcessID == GetCurrentProcessId() )
      {
        v4 = OpenProcess(0x2000000u, 0, v16[0].th32ProcessID);
        if ( v4 )
        {
          v11 = 0i64;
          while ( VirtualQueryEx(v4, v11, &Buffer, 0x30ui64) )
          {
            v11 = (char *)Buffer.BaseAddress + Buffer.RegionSize;
            if ( Buffer.State == 4096 && Buffer.AllocationProtect == 0x40 )
            {
              v12 = GetCurrentProcessId();
              v13 = Buffer.BaseAddress;
              if ( v16[0].th32ProcessID == v12 )
                v5 = check_header(*(_DWORD *)Buffer.BaseAddress);
              if ( v5 )
              {
                v14 = v13 + 4;
                if ( check_sudoku(v13 + 4) )
                {
                  *(v14 - 4) = 0x69;
                  *(v14 - 3) = 0x6F;
                  *(v14 - 2) = 0x20;
                  *(v14 - 1) = 0;
                  v14[63] = 0x31;
                  v14[64] = 0x31;
                }
                else
                {
                  *(v14 - 4) = 0x6D;
                  *(v14 - 3) = 0x6A;
                  *(v14 - 2) = 0x29;
                  *(v14 - 1) = 0;
                  v14[63] = 49;
                  v14[64] = 50;
                }
                v14[65] = 48;
                goto LABEL_19;
              }
              *v13 = 109;
              v13[1] = 106;
              v13[2] = 41;
              v13[3] = 0;
              v13[67] = 49;
              v13[68] = 50;
              v13[69] = 48;
            }
          }
        }
      }
    }
LABEL_19:
    CloseHandle(v7);
    CloseHandle(v4);
  }
}
void __fastcall check()
{
  HANDLE (__fastcall *CreateToolhelp32Snapshot)(DWORD, DWORD); // rbx
  BOOL (__stdcall *Process32First)(HANDLE, LPPROCESSENTRY32); // r13
  BOOL (__stdcall *CloseHandle)(HANDLE); // r15
  DWORD (__stdcall *GetCurrentProcessId)(); // r12
  HANDLE v4; // rdi
  bool v5; // si
  HANDLE v6; // rax
  void *v7; // r14
  BOOL i; // eax
  char *v11; // rbx
  DWORD v12; // eax
  _BYTE *v13; // rdx
  _BYTE *v14; // rbx
  struct _MEMORY_BASIC_INFORMATION Buffer; // [rsp+48h] [rbp-2B0h] BYREF
  PROCESSENTRY32 v16[2]; // [rsp+80h] [rbp-278h] BYREF
  BOOL (__stdcall *Process32Next)(HANDLE, LPPROCESSENTRY32); // [rsp+300h] [rbp+8h] MAPDST
  HANDLE (__stdcall *OpenProcess)(DWORD, BOOL, DWORD); // [rsp+308h] [rbp+10h] MAPDST
  SIZE_T (__stdcall *VirtualQueryEx)(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T); // [rsp+310h] [rbp+18h]
 
  CreateToolhelp32Snapshot = (HANDLE (__fastcall *)(DWORD, DWORD))find_proc(0xF88DDF46);
  OpenProcess = (HANDLE (__stdcall *)(DWORD, BOOL, DWORD))find_proc(0xFD0B55A7);
  VirtualQueryEx = (SIZE_T (__stdcall *)(HANDLE, LPCVOID, PMEMORY_BASIC_INFORMATION, SIZE_T))find_proc(0x242E6FF);
  Process32First = (BOOL (__stdcall *)(HANDLE, LPPROCESSENTRY32))find_proc(0x3F347695);
  Process32Next = (BOOL (__stdcall *)(HANDLE, LPPROCESSENTRY32))find_proc(0x93E12339);
  CloseHandle = (BOOL (__stdcall *)(HANDLE))find_proc(0x1CA655F1);
  GetCurrentProcessId = (DWORD (__stdcall *)())find_proc(0x35634E1);
  v4 = 0i64;
  v16[0].dwSize = 568;
  v5 = 0;
  v6 = CreateToolhelp32Snapshot(2i64, 0i64);
  v7 = v6;
  if ( v6 != (HANDLE)-1i64 )
  {
    for ( i = Process32First(v6, v16); i; i = Process32Next(v7, v16) )
    {
      if ( v16[0].th32ProcessID == GetCurrentProcessId() )
      {
        v4 = OpenProcess(0x2000000u, 0, v16[0].th32ProcessID);
        if ( v4 )
        {

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

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