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

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

2023-9-14 00:35
9228

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
__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;
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.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

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

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