2020 鼠年春节红包笔记【2 和 3 题】
本帖最后由 jixun66 于 2020-2-12 04:16 编辑Android 高级题做不来,因为不会动态调试也不会脱壳 hh
### 第 2 题 (Win32)
看上去像是 aspack/upx 简易版本?在 XP 下直接跳到 OEP 下 dump… 虽然不跨平台但在 XP 下能正常执行。
将 dump 出来的文件拉到 IDR 做分析,然后导出 map 文件导入到 OD 里。
同时在 IDR 软件中寻找密码框更新后的函数地址:
```asm
00617C3C > .55 push ebp ;_Unit71.TForm1.edtPwdChange_00617C3C
................
00617C5D .8D55 E0 lea edx,dword ptr ss:
00617C60 .8B83 D0030000 mov eax,dword ptr ds:
00617C66 .E8 4DA1F2FF call <2_1.Vcl.Controls.TControl.GetText_00541DB8>
00617C6B .8B45 E0 mov eax,dword ptr ss: ;eax = 键入的密码
00617C6E .85C0 test eax,eax
00617C70 .74 05 je short 2_1.00617C77
00617C72 .83E8 04 sub eax,0x4
00617C75 .8B00 mov eax,dword ptr ds:
00617C77 >83F8 0F cmp eax,0xF ;有 15 位字符
00617C7A .0F85 C9010000 jnz 2_1.00617E49
00617C80 .B2 01 mov dl,0x1
00617C82 .A1 586A6100 mov eax,dword ptr ds:
00617C87 .E8 F8EEFFFF call <2_1._Unit71.TIdHashMessageDigest4.Create_00616B84>
00617C8C .8BF0 mov esi,eax ;esi = pMd5
00617C8E .8D45 FC lea eax,dword ptr ss: ;<---- 储存位置
00617C91 .50 push eax
00617C92 .8D55 D8 lea edx,dword ptr ss:
00617C95 .8B83 D0030000 mov eax,dword ptr ds:
00617C9B .E8 18A1F2FF call <2_1.Vcl.Controls.TControl.GetText_00541DB8>
00617CA0 .8B45 D8 mov eax,dword ptr ss: ;eax = 键入的密码
00617CA3 .8D4D DC lea ecx,dword ptr ss:
00617CA6 .BA 07000000 mov edx,0x7
00617CAB .E8 3C76EFFF call <2_1.GetTextLeft> ;取出文本左边 edx 个字符
00617CB0 .8B55 DC mov edx,dword ptr ss: ;edx = 前 7 个字符
00617CB3 .33C9 xor ecx,ecx ;2_1.006221A0
00617CB5 .8BC6 mov eax,esi
00617CB7 .E8 E4E5FFFF call <2_1._Unit71.TIdHash.HashStringAsHex_006162A0> ;ebp-4 = MD5(left(serial, 7))
00617CBC .8D45 F8 lea eax,dword ptr ss: ;<---- 储存位置
................
00617CDF .E8 5076EFFF call <2_1.System.Generics.Defaults.sub_0050F334_0050F334> ;后面再取出 4 个字符
00617CE4 .8B55 D4 mov edx,dword ptr ss:
00617CE7 .33C9 xor ecx,ecx ;2_1.006221A0
00617CE9 .8BC6 mov eax,esi
00617CEB .E8 B0E5FFFF call <2_1._Unit71.TIdHash.HashStringAsHex_006162A0> ;<-- md5
................
00617D12 .8B55 CC mov edx,dword ptr ss: ;再取出最后 4 个字符
00617D15 .33C9 xor ecx,ecx ;2_1.006221A0
00617D17 .8BC6 mov eax,esi
00617D19 .E8 82E5FFFF call <2_1._Unit71.TIdHash.HashStringAsHex_006162A0> ;<-- md5
................
00617D3D .8B12 mov edx,dword ptr ds: ;edx = 0x804
00617D3F .8D45 FC lea eax,dword ptr ss: ;eax = MD5(前七位)
00617D42 .E8 597DE1FF call <2_1._Unit9.sub_0042FAA0_0042FAA0>
00617D47 .8B45 F0 mov eax,dword ptr ss:
00617D4A .BA B87E6100 mov edx,2_1.00617EB8 ;E7EE5F4653E31955CACC7CD68E2A7839
00617D4F .E8 A42DDFFF call <2_1.System.@UStrEqual_0040AAF8> ;第一串
00617D54 .0f9445 e7 sete byte ptr ss:
................
00617DA7 .BA 087F6100 mov edx,2_1.00617F08 ;ea6b2efbdd4255a9f1b3bbc6399b58f4
00617DAC .E8 472DDFFF call <2_1.System.@UStrEqual_0040AAF8> ;第二串
00617DB1 .0f9445 e6 sete byte ptr ss:
................
00617E08 .BA 587F6100 mov edx,2_1.00617F58 ;c8d46d341bea4fd5bff866a65ff8aea9
00617E0D .E8 E62CDFFF call <2_1.System.@UStrEqual_0040AAF8> ;第三串
00617E12 .0f9445 e5 sete byte ptr ss:
................
00617E3F .B8 A87F6100 mov eax,2_1.00617FA8 ;请把答案回复到论坛公众号!
00617E44 .E8 236BF5FF call <2_1._Unit54.sub_0056E96C_0056E96C>
```
当我找到第一串的时候,就在这个地址上搜寻字符串引用了,结果找到这三串:
| 地址 | 反汇编 | 文本字符串 |
| --: | ----- | :-------- |
| 00617D4A | `mov edx,2_1.00617EB8` | `E7EE5F4653E31955CACC7CD68E2A7839` |
| 00617DA7 | `mov edx,2_1.00617F08` | `ea6b2efbdd4255a9f1b3bbc6399b58f4` |
| 00617E08 | `mov edx,2_1.00617F58` | `c8d46d341bea4fd5bff866a65ff8aea9` |
| 00617E3F | `mov eax,2_1.00617FA8` | 请把答案回复到论坛公众号! |
拿去 MD5 数据在线查询,分别得到:
* `52pojie`
* `2019`
* `game`
三段字样。将其合并起来就是密码 `52pojie2019game`。
### 第 3 题 (安卓题)
因为不太懂怎么搞调试,所以把 so 文件解压出来,然后扔到 IDA 里去静态分析。
```c
int __fastcall Java_com_wuaipojie_crackme01_MainActivity_checkFlag__Ljava_lang_String_2(JNIEnv *a1, int a2, int a3)
{
jbyte *pParams; // r8
int tmpVal; // r10
JNIEnv *env; // r4
int v6; // r5
int v8; // r5
jbyteArray str__52pojie_2020_happy_chinese_new_year; // r11
jbyte *bytes_3_s35; // r6 MAPDST
unsigned int i; // r5
void *v13; // r1
void (__cdecl *fnGetByteArrayRegion)(JNIEnv *, jbyteArray, jsize, jsize, jbyte *); // r6
jsize v15; // r2
jstring str__MD5; // r0 MAPDST
_jmethodID *MD__getInstance; // r2 MAPDST
jobject MD5; // r6
_jmethodID *MD5__digest; // r2 MAPDST
jsize size_of_array; // r5
jsize start; // r6
jboolean char_of_i_mod_9; // r5
void *ClazzSB; // r6
int v26; // r5
int v27; // r5
jobject v29; // r5
_jmethodID *String__substring; // r2
jobject v31; // r6
int v33; // r5
int v34; //
jint v35; //
void *str__this_is_key; //
int v37; //
jbyteArray str__20200125; //
jobject md5_value; //
jint trimmedPassword; //
int String__equals; // MAPDST
int v43; //
int SB__toString; // MAPDST
int v45; //
int v46; //
int sb__init; //
int a3a; //
int StringClazz; //
int pFn; //
int sbInst; //
int MD; //
int a2a; //
jvalue jvalue; //
int v57; //
env = a1;
v6 = 0;
MD = 0;
a2a = 0;
pFn = 0;
sbInst = 0;
a3a = 0;
StringClazz = 0;
MD5__digest = 0;
MD__getInstance = 0;
v46 = 0;
sb__init = 0;
SB__toString = 0;
v45 = 0;
String__equals = 0;
v43 = 0;
((void (__fastcall *)(JNIEnv *, int))(*a1)->NewLocalRef)(a1, a2);
trimmedPassword = ((int (__fastcall *)(JNIEnv *, int))(*env)->NewLocalRef)(env, a3);
if ( !GetJavaFunction(env, &a2a, &a3a, 1, "android/os/Debug", "isDebuggerConnected") )
{
pParams = (jbyte *)jvalue;
v8 = (*env)->CallStaticBooleanMethodA(env, (jclass)a2a, (jmethodID)a3a, jvalue);
if ( !((*env)->ExceptionCheck(env) | v8) )
{
tmpVal = (int)(*env)->NewByteArray(env, 9);
if ( !(*env)->ExceptionCheck(env) )
goto LABEL_7;
}
goto LABEL_4;
}
LABEL_5:
while ( _stack_chk_guard != v57 )
{
LABEL_7:
v6 = 0;
(*env)->SetByteArrayRegion(env, (jbyteArray)tmpVal, 0, 9, "thisiskey52pojie_2020_happy_chinese_new_year20200125");
str__52pojie_2020_happy_chinese_new_year = (*env)->NewByteArray(env, 35);
if ( !(*env)->ExceptionCheck(env) )
{
v6 = 0;
(*env)->SetByteArrayRegion(
env,
str__52pojie_2020_happy_chinese_new_year,
0,
35,
"52pojie_2020_happy_chinese_new_year20200125");
str__20200125 = (*env)->NewByteArray(env, 8);
if ( !(*env)->ExceptionCheck(env) )
{
v6 = 0;
(*env)->SetByteArrayRegion(env, str__20200125, 0, 8, "20200125");
bytes_3_s35 = (jbyte *)(*env)->NewByteArray(env, 35);
if ( !(*env)->ExceptionCheck(env) )
{
i = 0;
str__this_is_key = (void *)tmpVal;
do
{
if ( !i || i & 3 )
{
if ( !str__52pojie_2020_happy_chinese_new_year )
goto LABEL_41;
v13 = str__52pojie_2020_happy_chinese_new_year;
v15 = i;
fnGetByteArrayRegion = (*env)->GetByteArrayRegion;
}
else
{
v13 = str__20200125;
if ( !str__20200125 )
goto LABEL_41;
fnGetByteArrayRegion = (*env)->GetByteArrayRegion;
v15 = (i >> 2) - 1;
}
fnGetByteArrayRegion(env, v13, v15, 1, pParams);
tmpVal = jvalue.z;
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_4;
if ( !bytes_3_s35 )
{
LABEL_41:
sub_4EC0(env, "java/lang/NullPointerException", "NullPointerException");
goto LABEL_4;
}
jvalue.z = tmpVal;
(*env)->SetByteArrayRegion(env, bytes_3_s35, i, 1, pParams);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_4;
}
while ( i++ < 34 ); // for (i = 0; i <= 34; i++)
str__MD5 = (*env)->NewStringUTF(env, "MD5");
if ( !MD__getInstance
&& GetJavaFunction(env, &MD, (int *)&MD__getInstance, 1, "java/security/MessageDigest", "getInstance") )
{
goto LABEL_89;
}
jvalue.i = (jint)str__MD5;
MD5 = (*env)->CallStaticObjectMethodA(env, (jclass)MD, MD__getInstance, jvalue);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
if ( str__MD5 )
((void (__fastcall *)(JNIEnv *, jstring))(*env)->DeleteLocalRef)(env, str__MD5);
if ( !MD5 )
{
ThrowException:
sub_4EC0(env, "java/lang/NullPointerException", "NullPointerException");
goto LABEL_89;
}
if ( !MD5__digest
&& GetJavaFunction(env, &MD, (int *)&MD5__digest, 0, "java/security/MessageDigest", "digest") )
{
goto LABEL_89;
}
jvalue.i = (jint)bytes_3_s35;
md5_value = (*env)->CallObjectMethodA(env, MD5, MD5__digest, jvalue);
if ( (*env)->ExceptionCheck(env) )
goto LABEL_89;
(*env)->DeleteLocalRef(env, MD5);
if ( !md5_value )
goto ThrowException;
size_of_array = (*env)->GetArrayLength(env, md5_value);
if ( (*env)->ExceptionCheck(env) )
goto LABEL_89;
start = 0;
// ???
while ( 1 )
{
pParams = (jbyte *)(0x38E38E39 * (unsigned __int64)(unsigned int)start >> 32);
if ( start >= size_of_array )
break;
//(* env) -> GetByteArrayRegion (env, array, 0, len, (jbyte *)buf);
(*env)->GetByteArrayRegion(env, md5_value, start, 1, (jbyte *)jvalue);
tmpVal = jvalue.z;
if ( (*env)->ExceptionCheck(env) )
goto LABEL_89;
if ( !str__this_is_key )
goto ThrowException;
// xor:
// MD5("???"),
// bytes_0_s9
(*env)->GetByteArrayRegion(env, str__this_is_key, start % 9u, 1, (jbyte *)jvalue);
char_of_i_mod_9 = jvalue.z;
if ( !(*env)->ExceptionCheck(env) )
{
jvalue.z = char_of_i_mod_9 ^ tmpVal;
(*env)->SetByteArrayRegion(env, md5_value, start, 1, (jbyte *)jvalue);
if ( !(*env)->ExceptionCheck(env) )
{
size_of_array = (*env)->GetArrayLength(env, md5_value);
++start;
if ( !(*env)->ExceptionCheck(env) )
continue;
}
}
goto LABEL_89;
}
if ( str__this_is_key )
((void (__fastcall *)(JNIEnv *, void *))(*env)->DeleteLocalRef)(env, str__this_is_key);
if ( !sbInst && CreateClassInstance(env, &sbInst, (int)"java/lang/StringBuilder") )
goto LABEL_89;
ClazzSB = (void *)((int (__fastcall *)(JNIEnv *))(*env)->AllocObject)(env);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
v26 = ((int (__fastcall *)(JNIEnv *, jobject))(*env)->GetArrayLength)(env, md5_value);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
if ( !ClazzSB )
goto ThrowException;
if ( !sb__init && GetJavaFunction(env, &sbInst, &sb__init, 0, "java/lang/StringBuilder", "<init>") )
goto LABEL_89;
jvalue.i = 2 * v26;
((void (__fastcall *)(JNIEnv *, void *))(*env)->CallVoidMethodA)(env, ClazzSB);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
v34 = ((int (__fastcall *)(JNIEnv *, jobject))(*env)->GetArrayLength)(env, md5_value);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
if ( v34 >= 1 )
{
v37 = 0;
v35 = 0;
while ( 1 )
{
((void (__fastcall *)(JNIEnv *, jobject, int, signed int))(*env)->GetByteArrayRegion)(
env,
md5_value,
v37,
1);
pParams = (jbyte *)jvalue.z;
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
break;
if ( (unsigned int)pParams <= 0xF )
{
if ( v35 )
((void (__fastcall *)(JNIEnv *, jint))(*env)->DeleteLocalRef)(env, v35);
v35 = ((int (__fastcall *)(JNIEnv *, const char *))(*env)->NewStringUTF)(env, "0");
if ( !v46 && GetJavaFunction(env, &sbInst, &v46, 0, "java/lang/StringBuilder", "append") )
break;
jvalue.i = v35;
v27 = ((int (__fastcall *)(JNIEnv *, void *))(*env)->CallObjectMethodA)(env, ClazzSB);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
break;
if ( v27 )
((void (__fastcall *)(JNIEnv *, int))(*env)->DeleteLocalRef)(env, v27);
}
if ( !v45 && GetJavaFunction(env, &pFn, &v45, 1, "java/lang/Integer", "toHexString") )
break;
jvalue.i = (jint)pParams;
pParams = (jbyte *)((int (__fastcall *)(JNIEnv *, int))(*env)->CallStaticObjectMethodA)(env, pFn);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
break;
if ( bytes_3_s35 )
((void (__fastcall *)(JNIEnv *, jbyte *))(*env)->DeleteLocalRef)(env, bytes_3_s35);
if ( !v46 && GetJavaFunction(env, &sbInst, &v46, 0, "java/lang/StringBuilder", "append") )
break;
jvalue.i = (jint)pParams;
tmpVal = ((int (__fastcall *)(JNIEnv *, void *))(*env)->CallObjectMethodA)(env, ClazzSB);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
break;
if ( tmpVal )
((void (__fastcall *)(JNIEnv *, int))(*env)->DeleteLocalRef)(env, tmpVal);
++v37;
bytes_3_s35 = pParams;
if ( v37 >= v34 )
goto LABEL_75;
}
LABEL_89:
v33 = ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionOccurred)(env);
((void (__fastcall *)(JNIEnv *))(*env)->ExceptionClear)(env);
if ( !sub_50EC(env, v33, "java/lang/Exception") )
{
((void (__fastcall *)(JNIEnv *, int))(*env)->Throw)(env, v33);
((void (__fastcall *)(JNIEnv *, int))(*env)->DeleteLocalRef)(env, v33);
}
LABEL_4:
v6 = 0;
goto LABEL_5;
}
LABEL_75:
if ( !SB__toString && GetJavaFunction(env, &sbInst, &SB__toString, 0, "java/lang/StringBuilder", "toString") )
goto LABEL_89;
v29 = (*env)->CallObjectMethodA(env, ClazzSB, (jmethodID)SB__toString, jvalue);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
((void (__fastcall *)(JNIEnv *, void *))(*env)->DeleteLocalRef)(env, ClazzSB);
if ( !v29 )
goto ThrowException;
String__substring = (_jmethodID *)v43;
if ( !v43 )
{
if ( GetJavaFunction(env, &StringClazz, &v43, 0, "java/lang/String", "substring") )
goto LABEL_89;
String__substring = (_jmethodID *)v43;
}
jvalue.i = 31;
jvalue.i = 1;
v31 = (*env)->CallObjectMethodA(env, v29, String__substring, jvalue);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
((void (__fastcall *)(JNIEnv *, jobject))(*env)->DeleteLocalRef)(env, v29);
if ( !v31 )
goto ThrowException;
if ( !String__equals && GetJavaFunction(env, &StringClazz, &String__equals, 0, "java/lang/String", "equals") )
goto LABEL_89;
jvalue.i = trimmedPassword;
v6 = (*env)->CallBooleanMethodA(env, v31, (jmethodID)String__equals, jvalue);
if ( ((int (__fastcall *)(JNIEnv *))(*env)->ExceptionCheck)(env) )
goto LABEL_89;
}
}
}
}
return v6;
}
```
大致过程:
1. 将字符串 "52pojie_2020_happy_chinese_new_year" 进行变形
2. 根据 key 来进行 xor 循环计算
3. 计算 MD5,并转换为 HEX 表示形式 (32 字符长度)
4. 去掉首位各一个字符,得到的字符串即为密码。
其实 `onClick` 函数也有看了一看,不过只是基本的裁剪空白文本并检查长度是否为 `30`。
整理成 JS:
```js
{
const key1 = 'thisiskey'; // 9 个字符
const key2 = '20200125';
const text = '52pojie_2020_happy_chinese_new_year';
const result = [];
for (let i = 0; i < text.length; i++) {
let str, idx;
// 我被 IDA F5 出来的这个逻辑给弄晕了,只好照抄了哈哈
// if (!i || i & 3)
// 52pojie_2020_happy_chinese_new_year
// 2 0 2 0 0 1 2 5
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// 52po2ie_00202hap0y_c0ine1e_n2w_y5ar
if ((i === 0) || ((i & 3) !== 0)) {
str = text;
idx = i;
} else {
str = key2;
idx = (i >> 2) - 1;
}
result.push(str);
}
// 我直接粘贴到第三方网站查的 MD5
// result === "52po2ie_00202hap0y_c0ine1e_n2w_y5ar"
// md5(result) === "3ABE761061B420AA4CB37F40A7B257AD"
const md5_bytes = [];
'3ABE761061B420AA4CB37F40A7B257AD'.replace(/../g, z => {
md5_bytes.push(parseInt(z, 16));
});
const md5_transformed = md5_bytes.map((x, i) => x ^ key1.charCodeAt(i % key1.length));
const password = md5_transformed.map(x => `0${x.toString(16)}`.slice(-2)).join('').slice(1, -1);
}
```
计算后得到密码 `ed61f6308c74bcf35c71729d4db24c`。
snrtdwss 发表于 2020-2-13 11:26
请教下 我导入不显示 你分析那样的代码 怎么回事 不显示.thisiskey52pojie_2020_happy_chinese_new_year202 ...
1. 把 a1 变量类型改成 "JNIEnv *",并调整对应变量的类型
2. 之后会出现一个 "&unk1234" 这样的引用,点进去,改成 "char" 之类的类型(xyz 为字符串大小)
3. IDA 内刷新伪代码,应该会出现字符串引用了 yaerhuo 发表于 2020-2-12 04:55
特牛的未来教育激活器的大佬,膜拜,第一道题今年解出来了,第二道安卓题一脸懵,不过看了半天还是不大懂
大多数情况下都是连蒙带猜... 外加一点运气w 特牛的未来教育激活器的大佬,膜拜,第一道题今年解出来了,第二道安卓题一脸懵,不过看了半天还是不大懂 感谢分享 感谢楼主分享。。。。。 原版UPX,只是修改了下把UPX压缩时候原始PE信息写入那块去掉了。 支持楼主 收藏学习一下 做个笔记,学到了