-
-
[原创]KCTF2021第7题WP
-
2021-12-3 10:14 14223
-
1.先尝试搜寻提示字符串未找到,然后祭出CE,搜自己输入的文本,下访问断点。
找到关键逻辑函数:0041D2D0
对逻辑逐一断点调试,分析出每个步骤的功能
-
-
-
2.使用IDA进行动态调试,分析传入序列号base64取返回字符串这个函数
看起来是个thiscall, ecx未知,参数1位传入的BASE64,参数2为接收的BUF
单步走一下
-
-
-
3.跟进取返回结果函数内部分析逻辑(程序BASE为730000)
继续跟进74D840(41D840)
这里发现将一个函数地址 | 上0x3300000000, 在下面再取低8位进行调用,算一个小干扰
继续跟进7456F0(4156F0),这里有点难看了,不过没关系,动态调试发现a3就是初始传入的函数地址7455AC(4155AC)
跟进7455AC(4155AC)
发现在资源段,IDA不能识别,需要手动将其设置为函数,对7455AC处右键-->undefine-->code-->create function
然后我们进入到关键函数了,分析发现底下一个判断就是返回文本"正确"or"错误"
继续分析上续判断条件,看起来是从地址0xFFFFFE4B,0xFFFFFE50,0xFFFFFE12取出一共48个字节数据
-
-
-
4.想在取48byte数据后设置一下断点看看数据,结果尝试了CE、OD、X32dbg、IDA调试器后,发现在这个算法内断点都会跳到win32u.dll里去。
查阅资料后发现可能是程序通过WOW64将关键算法转为64位形态去运行了
-
-
-
5.尝试了N遍断点后,换到IDA的windbg调试器发现可以断点!(之前都是选的local windows debug)
对算法下断点,查看ebp-30处48byte的数据如下,是一串BASE64字符串,每次输入不同此值都不变
GYldGg-iIoJlPX9hPXpjPqfdEY21B01TBTzeGqfKNR!!
-
-
-
6.注入DLL,调用程序函数穷举这串BASE64,利用BASE64的3字节转4字节特性对BASE64文本前4个字符进行穷举,发现这个f l a就觉得有戏了("fla"的BASE64为"GYld")
完善穷举代码,输出所有字节
当然通过找码表可以实现更快的解密算法,只是当时觉得穷举起来省事
程序代码如下,由于库版本可能不同,我的string传入程序会崩溃,临时构造了一个string结构体。函数返回的文本还存在内存泄漏问题。
FLAG:
flag{2021-10-04-yangyangbudeyi}
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <vector> #include <map> using namespace std; #include <windows.h> #include <stdio.h> #include "Log/Log.h" #include "MinHook/include/MinHook.h" #if _DEBUG #pragma comment(lib, "MinHook\\lib\\libMinHook-x86-v141-mdd.lib") #else #pragma comment(lib, "MinHook\\lib\\libMinHook-x86-v141-md.lib") #endif DWORD g_pModule; struct MyString { char * ptr = NULL; char buf[ 12 ] = { 0 }; int size = 0 ; int serve = 0 ; }; / / base64 ( % string, const char * ) int (__cdecl * g_myfunc_41E530)( int a1, int a2); void Init() { g_pModule = (DWORD)GetModuleHandleA(NULL); LOG_INFO( "g_pModule[0x%x]" , g_pModule); * (DWORD * )&g_myfunc_41E530 = g_pModule + 0x1E530 ; / / 程序BASE函数地址 LOG_INFO( "g_myfunc_41E530[%p]" , g_myfunc_41E530); } void MyBase64(string str , string& str_base64, bool isPrint = true) { str_base64.clear(); MyString a1; MyString a2; if ( str .length() < 18 ) { string tmp; for (size_t i = 0 ; i < 18 - str .length(); i + + ) { tmp + = "1" ; } str + = tmp; } a2.ptr = (char * )calloc( 1 , str .length() + 1 ); if (!a2.ptr) return ; strcpy(a2.ptr, str .c_str()); a2.size = str .length(); a2.serve = str .length() + 1 ; / / LOG_INFO( "a2[%s]" , a2.ptr); g_myfunc_41E530(( int )&a1, ( int )&a2); if (a1.ptr) { if (isPrint) { LOG_INFO( "[%s][%s]" , str .c_str(), a1.ptr); } str_base64 = a1.ptr; } free(a2.ptr); } std:: map < int , string> tmpMap; void * threadfunc(void * arg) { Sleep( 1000 ); string str1; for (size_t i = 0 ; i < 10 ; i + + ) { tmpMap[i] = "XXX" ; } char buf[ 4 ] = { 0 }; char szKey[] = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/{}-=" ; int i0 = 0 ; int i1 = 0 ; int i2 = 0 ; for (i0 = 0 ; i0 < sizeof(szKey); i0 + + ) { / / LOG_INFO( "i0==%d" , i0); buf[ 0 ] = szKey[i0]; for (i1 = 0 ; i1 < sizeof(szKey); i1 + + ) { buf[ 1 ] = szKey[i1]; for (i2 = 0 ; i2 < sizeof(szKey); i2 + + ) { buf[ 2 ] = szKey[i2]; MyBase64(buf, str1, false); if (str1.substr( 0 , 4 ) = = "GYld" ) { if (tmpMap[ 0 ] ! = "XXX" ) continue ; tmpMap[ 0 ] = buf; LOG_INFO( "1 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "Gg-i" ) { if (tmpMap[ 1 ] ! = "XXX" ) continue ; tmpMap[ 1 ] = buf; LOG_INFO( "2 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "IoJl" ) { if (tmpMap[ 2 ] ! = "XXX" ) continue ; tmpMap[ 2 ] = buf; LOG_INFO( "3 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "PX9h" ) { if (tmpMap[ 3 ] ! = "XXX" ) continue ; tmpMap[ 3 ] = buf; LOG_INFO( "4 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "PXpj" ) { if (tmpMap[ 4 ] ! = "XXX" ) continue ; tmpMap[ 4 ] = buf; LOG_INFO( "5 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "Pqfd" ) { if (tmpMap[ 5 ] ! = "XXX" ) continue ; tmpMap[ 5 ] = buf; LOG_INFO( "6 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "EY21" ) { if (tmpMap[ 6 ] ! = "XXX" ) continue ; tmpMap[ 6 ] = buf; LOG_INFO( "7 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "B01T" ) { if (tmpMap[ 7 ] ! = "XXX" ) continue ; tmpMap[ 7 ] = buf; LOG_INFO( "8 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "BTze" ) { if (tmpMap[ 8 ] ! = "XXX" ) continue ; tmpMap[ 8 ] = buf; LOG_INFO( "9 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } if (str1.substr( 0 , 4 ) = = "GqfK" ) { if (tmpMap[ 9 ] ! = "XXX" ) continue ; tmpMap[ 9 ] = buf; LOG_INFO( "10 OK!!! %c %c %c" , szKey[i0], szKey[i1], szKey[i2]); } } } } string szFlag; for (size_t i = 0 ; i < 10 ; i + + ) { szFlag + = tmpMap[i]; } LOG_INFO( "szFlag1: %s" , szFlag.c_str()); / / 30 位 有 2 个!号,所以剩下 1 位 szFlag + = "0" ; for (i0 = 0 ; i0 < sizeof(szKey); i0 + + ) { szFlag[ 30 ] = szKey[i0]; MyBase64(szFlag, str1, false); if (str1 = = "GYldGg-iIoJlPX9hPXpjPqfdEY21B01TBTzeGqfKNR!!" ) { LOG_INFO( "FLAG: %s" , szFlag.c_str()); } } while (true) { Sleep( 100 ); } return NULL; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: Init(); CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)threadfunc, NULL, 0 , NULL); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break ; } return TRUE; } extern "C" void _declspec(dllexport) aaa() { } |
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法