0x00 前言
上一文 PPPoE中间人拦截以及校园网突破漫谈我们谈到使用 PPPoE 拦截来获取真实的账号密码。
在这个的基础上,我对校园网客户端进行了逆向,得到了拨号加密算法。
0x01 准备工作
首先查壳,发现这个版本没壳了,我记得之前好像是加过 vmp 的呀,不管了。
然后我们看看目录下的 dll 导出表看看有没有什么好东西
AidcComm.dll 里面有这些东西,看来这个极大可能会是我们的目标。
我们再看看主程序的导入表,发现主程序的导入表里面并没有这个 dll,那我们动态调试的时候应该怎么断到这个 dll 中去呢。
没有导入表说明没有 .lib,那有可能是通过 LoadLibrary 加载的 dll,至于自实现 peloader,我觉得应该这个软件应该不会是这样。
看看就知道了。
直接用 x32dbg 和 IDA 开始看。
0x02 逆向过程
x32dbg 打开主程序,然后 bp LoadLibraryW
,再重新载入程序,我们可以一步步运行发现 AidcComm.dll 被载入了。
然后运行到用户代码处
我们可以看到此时 eax 寄存器的值为 55870000,这个就是 LoadLibrary 返回的 HANDLE。一般思路来说,接下来就是用 GetProcAddress 获取导出表函数的地址了。
继续往下走几步,即可发现我们的猜测并没有错误。
从这张图我们可以看到主程序获取了 AidcComm.GetPWD 和 AidcComm.GetRegularAccount 的地址。
那我们通过 call 之后的 eax 跳转过去在这两个函数的地址下断,直接跑起来。
然后我们会发现在 AidcComm.GetRegularAccount 断下来了,传入的参数可以在堆栈窗口中看到。
我们去 IDA 分析 GetRegularAccount 这个函数,同时在调试器这边动态跟(这个我已经分析过了,所以有的变量和函数名我已经改过了)
首先最直观的就是账号的变换,账号只需要加上前缀 !^Wnds0
即可(但其实加密出来后,主程序这个给它又加了一个后缀 @hbxy
)。(从调试器可以看到)
密码我们直接跟到 GetPWD 里面去看。
通过调试器我们可以观察出,这个分支结构只会执行 a2 == 1
这个分支。
看来是通过下面这个函数加密的了。(我给他改了名 encryptPwdWithKey)
我们进到 encryptPwdWithKey(void *password, char *key, rsize_t SizeInBytes)
这个函数去查看。
通过分析我们可以得出大致上的流程
1. password 用 key RC4 一下得到 A
2. 把 A md5 一下得到 B,如果第 11 位为奇数,取 B 的前 16 位,偶数就后 16 位,得到 C
3. C 再用 key RC4 一下得到 D
4. D 再 md5 一下,取 [8:24]得到 E
也就是最后得到的 E 是加密之后的。
可能有的小伙伴不明白为什么会是 RC4,这里有几个提示的地方,第一是这个字符串的提示,第二是 RC4 加密流程是很容易分辨的,这个靠经验了。
但是我们发现我们截取出来的密码和这个是有点小不一样的。通过调试,可以看到在 GetRegularAccount 函数加密出来后,又调用了一个函数,这个函数我给它重命名为 fixHBKey 了。
我们跟进去看看
代码并不长,我们可以直接调试器分析,如果你想用 IDA 也是可以的,IDA 可以搜索上图中的 <<< FixHBKey: %s <<<
这个字符串来定位这个函数。
或者我们可以看到这个函数的入口地址为 001115D0
,这个 exe 的加载基址我们可以往上滑到顶看到为 000F1000
,两个之间的差值为 205D0
,
然后再把这个差值加上 IDA 加载的基址,即可找到这个函数。
这个函数的大致作用就是修改上面我们得到的 E
- E[今天几号日期 % 16] 替换为 'b' 得到最后的密码
这块我们是搞清楚了,那 key 是怎么来的呢。
这个我们就需要大量借助调试器了,我们重启一下主程序,然后在上面的分析基础上找到这个 key 第一次出现的地方,我们可以发现
在 AidcRes 偏移 10110 处即为 key 的生成函数。
这个函数巨长,同样的,我们借助之前的方法在 IDA 中找到这个函数,我这里直接按偏移,可以看到在 sub_420110 即为我们的加密函数,
这里我已经重命名为 generateKey。
这个函数太长了,我无法截全图,我直接丢代码然后分析,这里分析建议大家调试结合代码来看,不然一头雾水。其中大量的必要变量和函数我已经重命名,方便大家阅读。
int __thiscall generateKey(char *this, int a2, char a3, int a4, int a5, int a6, int a7, int a8)
{
int v8; // eax
int v9; // edx
int v11; // [esp+8h] [ebp-37Ch]
char *v12; // [esp+20h] [ebp-364h]
int len_username_b_MonthDay; // [esp+24h] [ebp-360h]
char *v14; // [esp+28h] [ebp-35Ch]
int len_bUsernameMonthDay; // [esp+2Ch] [ebp-358h]
char *v16; // [esp+30h] [ebp-354h]
char *mem_17; // [esp+34h] [ebp-350h]
int v18; // [esp+38h] [ebp-34Ch]
int lenMonthDay; // [esp+3Ch] [ebp-348h]
int lenUsername; // [esp+40h] [ebp-344h]
int v21; // [esp+44h] [ebp-340h]
int v22; // [esp+48h] [ebp-33Ch]
int *v23; // [esp+4Ch] [ebp-338h]
int v24; // [esp+50h] [ebp-334h]
const char *v25; // [esp+54h] [ebp-330h]
int len_HbKeyGa; // [esp+58h] [ebp-32Ch]
int lenHbKeyGa; // [esp+5Ch] [ebp-328h]
char *pMem_64_a; // [esp+60h] [ebp-324h]
int len_HbKeyGb; // [esp+64h] [ebp-320h]
int lenHbKeyGb; // [esp+68h] [ebp-31Ch]
char *pMem_64_b; // [esp+6Ch] [ebp-318h]
int v32; // [esp+70h] [ebp-314h]
int v33; // [esp+74h] [ebp-310h]
int v34; // [esp+78h] [ebp-30Ch]
int v35; // [esp+7Ch] [ebp-308h]
int len_monthDay_Username_b; // [esp+80h] [ebp-304h]
char *v37; // [esp+84h] [ebp-300h]
int len_username_MonthDay_b; // [esp+88h] [ebp-2FCh]
LPVOID lp_mix_md5_1; // [esp+8Ch] [ebp-2F8h]
size_t v40; // [esp+90h] [ebp-2F4h]
int v41; // [esp+94h] [ebp-2F0h]
LPVOID v42; // [esp+98h] [ebp-2ECh]
LPVOID v43; // [esp+9Ch] [ebp-2E8h]
LPVOID v44; // [esp+A0h] [ebp-2E4h]
int index3; // [esp+A4h] [ebp-2E0h]
int index2; // [esp+A8h] [ebp-2DCh]
char *pHbKeyGa; // [esp+ACh] [ebp-2D8h]
int index6; // [esp+B0h] [ebp-2D4h]
int index5; // [esp+B4h] [ebp-2D0h]
_DWORD *md5_monthDay_Username_b; // [esp+B8h] [ebp-2CCh]
_DWORD *md5_username_b_MonthDay; // [esp+BCh] [ebp-2C8h]
_DWORD *md5_username_MonthDay_b; // [esp+C0h] [ebp-2C4h]
void *mix_md5_1; // [esp+C4h] [ebp-2C0h]
int md5_1_pLus3remainder4; // [esp+C8h] [ebp-2BCh]
int md5_bUsernameMonthDay; // [esp+CCh] [ebp-2B8h]
char *pHbKeyGb; // [esp+D0h] [ebp-2B4h]
void *v57; // [esp+D4h] [ebp-2B0h]
void *v58; // [esp+D8h] [ebp-2ACh]
int md5_4_plus5remainer4; // [esp+DCh] [ebp-2A8h]
void *mix_md5_2; // [esp+E0h] [ebp-2A4h]
const char *userName; // [esp+E4h] [ebp-2A0h]
char *monthDay; // [esp+E8h] [ebp-29Ch]
char *bUsernameMonthDay; // [esp+ECh] [ebp-298h]
char *username_b_MonthDay; // [esp+F0h] [ebp-294h]
char *username_MonthDay_b; // [esp+F4h] [ebp-290h]
char *monthDay_Username_b; // [esp+F8h] [ebp-28Ch]
char *p_HbKeyGb; // [esp+FCh] [ebp-288h]
char *p_HbKeyGa; // [esp+100h] [ebp-284h]
const char *username; // [esp+104h] [ebp-280h]
_DWORD *md5_2; // [esp+108h] [ebp-27Ch]
_DWORD *md5_3; // [esp+10Ch] [ebp-278h]
int index1; // [esp+114h] [ebp-270h]
int index4; // [esp+118h] [ebp-26Ch]
int temp1; // [esp+11Ch] [ebp-268h]
int temp2; // [esp+120h] [ebp-264h]
_DWORD *md5_4; // [esp+124h] [ebp-260h]
int md5_1; // [esp+128h] [ebp-25Ch]
size_t SizeInBytes; // [esp+134h] [ebp-250h]
char *DstBuf; // [esp+138h] [ebp-24Ch]
char *pThis; // [esp+13Ch] [ebp-248h]
int v81; // [esp+140h] [ebp-244h]
int v82; // [esp+144h] [ebp-240h]
int v83; // [esp+148h] [ebp-23Ch]
int v84; // [esp+14Ch] [ebp-238h]
int v85; // [esp+150h] [ebp-234h]
int v86; // [esp+154h] [ebp-230h]
int v87; // [esp+158h] [ebp-22Ch]
int v88; // [esp+15Ch] [ebp-228h]
char hbKey; // [esp+160h] [ebp-224h]
char v90; // [esp+161h] [ebp-223h]
char hbKeyGa; // [esp+1E4h] [ebp-1A0h]
char mem_64_a; // [esp+1E5h] [ebp-19Fh]
char hbKeyGb; // [esp+228h] [ebp-15Ch]
char mem_64_b; // [esp+229h] [ebp-15Bh]
char v95; // [esp+22Fh] [ebp-155h]
char v96[4]; // [esp+26Ch] [ebp-118h]
char v97[5]; // [esp+270h] [ebp-114h]
int v98; // [esp+275h] [ebp-10Fh]
int v99; // [esp+279h] [ebp-10Bh]
int v100; // [esp+27Dh] [ebp-107h]
int v101; // [esp+281h] [ebp-103h]
int v102; // [esp+285h] [ebp-FFh]
__int16 v103; // [esp+289h] [ebp-FBh]
char v104; // [esp+28Bh] [ebp-F9h]
char v105[4]; // [esp+28Ch] [ebp-F8h]
char v106[5]; // [esp+290h] [ebp-F4h]
int v107; // [esp+295h] [ebp-EFh]
int v108; // [esp+299h] [ebp-EBh]
int v109; // [esp+29Dh] [ebp-E7h]
int v110; // [esp+2A1h] [ebp-E3h]
int v111; // [esp+2A5h] [ebp-DFh]
__int16 v112; // [esp+2A9h] [ebp-DBh]
char v113; // [esp+2ABh] [ebp-D9h]
char v114[4]; // [esp+2ACh] [ebp-D8h]
char v115[5]; // [esp+2B0h] [ebp-D4h]
int v116; // [esp+2B5h] [ebp-CFh]
int v117; // [esp+2B9h] [ebp-CBh]
int v118; // [esp+2BDh] [ebp-C7h]
int v119; // [esp+2C1h] [ebp-C3h]
int v120; // [esp+2C5h] [ebp-BFh]
__int16 v121; // [esp+2C9h] [ebp-BBh]
char v122; // [esp+2CBh] [ebp-B9h]
char v123[4]; // [esp+2CCh] [ebp-B8h]
char v124[5]; // [esp+2D0h] [ebp-B4h]
int v125; // [esp+2D5h] [ebp-AFh]
int v126; // [esp+2D9h] [ebp-ABh]
int v127; // [esp+2DDh] [ebp-A7h]
int v128; // [esp+2E1h] [ebp-A3h]
int v129; // [esp+2E5h] [ebp-9Fh]
__int16 v130; // [esp+2E9h] [ebp-9Bh]
char v131; // [esp+2EBh] [ebp-99h]
char char_array_29_2[29]; // [esp+2ECh] [ebp-98h]
__int16 v133; // [esp+309h] [ebp-7Bh]
char v134; // [esp+30Bh] [ebp-79h]
char char_array_29_1[29]; // [esp+30Ch] [ebp-78h]
__int16 v136; // [esp+329h] [ebp-5Bh]
char v137; // [esp+32Bh] [ebp-59h]
char char_array_29_3[29]; // [esp+32Ch] [ebp-58h]
__int16 v139; // [esp+349h] [ebp-3Bh]
char v140; // [esp+34Bh] [ebp-39h]
char char_array_29_4[29]; // [esp+34Ch] [ebp-38h]
__int16 v142; // [esp+369h] [ebp-1Bh]
char v143; // [esp+36Bh] [ebp-19h]
char month_day; // [esp+36Ch] [ebp-18h]
int v145; // [esp+36Dh] [ebp-17h]
int v146; // [esp+380h] [ebp-4h]
pThis = this;
v41 = 0;
v146 = 0;
username = 0;
v40 = sub_421680("@hbxy", 0);
if ( v40 != -1 )
{
v33 = sub_421630((int)&v11, 0, v40);
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator=(v33);
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string<char,std::char_traits<char>,std::allocator<char>>(&v11);
}
username = (const char *)get_username(&a3);
userName = username;
v25 = username + 1;
userName += strlen(userName);
v24 = ++userName - (username + 1);
lenUsername = userName - (username + 1);
month_day = 0;
v145 = 0;
strftime(&month_day, 5u, "%m%d", (const struct tm *)(pThis + 8));
monthDay = &month_day;
v23 = &v145;
monthDay += strlen(monthDay);
v21 = ++monthDay - (char *)&v145;
lenMonthDay = monthDay - (char *)&v145;
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, ">>> GetHBKey: %s >>>", &month_day);
v18 = 1;
SizeInBytes = lenMonthDay + lenUsername + 2;
mem_17 = (char *)malloc(SizeInBytes);
DstBuf = mem_17;
memset(mem_17, 0, SizeInBytes);
sprintf_s(DstBuf, SizeInBytes, "%c%s%s", pThis[4], username, &month_day);// "b177628979080516"
bUsernameMonthDay = DstBuf;
v16 = DstBuf + 1;
bUsernameMonthDay += strlen(bUsernameMonthDay);
len_bUsernameMonthDay = ++bUsernameMonthDay - (DstBuf + 1);
md5_bUsernameMonthDay = md5_StrWithLength(DstBuf, bUsernameMonthDay - (DstBuf + 1));// 5e64fdaa6449e2abb9693f2757c11652
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(
pThis,
"[HBKEY] mdata1: %s [%s]",
DstBuf,
md5_bUsernameMonthDay);
memset(DstBuf, 0, SizeInBytes);
sprintf_s(DstBuf, SizeInBytes, "%s%c%s", username, pThis[4], &month_day);// "17762897908b0516"
username_b_MonthDay = DstBuf;
v14 = DstBuf + 1;
username_b_MonthDay += strlen(username_b_MonthDay);
len_username_b_MonthDay = ++username_b_MonthDay - (DstBuf + 1);
md5_username_b_MonthDay = (_DWORD *)md5_StrWithLength(DstBuf, username_b_MonthDay - (DstBuf + 1));// 16dffe496172e2fb1bdb9b2002bfb5a5
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(
pThis,
"[HBKEY] mdata2: %s [%s]",
DstBuf,
md5_username_b_MonthDay);
memset(DstBuf, 0, SizeInBytes);
sprintf_s(DstBuf, SizeInBytes, "%s%s%c", username, &month_day, pThis[4]);// "177628979080516b"
username_MonthDay_b = DstBuf;
v12 = DstBuf + 1;
username_MonthDay_b += strlen(username_MonthDay_b);
len_username_MonthDay_b = ++username_MonthDay_b - (DstBuf + 1);
md5_username_MonthDay_b = (_DWORD *)md5_StrWithLength(DstBuf, username_MonthDay_b - (DstBuf + 1));// 6614da7943beed0e7baafc0be7fb624c
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(
pThis,
"[HBKEY] mdata3: %s [%s]",
DstBuf,
md5_username_MonthDay_b);
memset(DstBuf, 0, SizeInBytes);
sprintf_s(DstBuf, SizeInBytes, "%s%s%c", &month_day, username, pThis[4]);// "051617762897908b"
monthDay_Username_b = DstBuf;
v37 = DstBuf + 1;
monthDay_Username_b += strlen(monthDay_Username_b);
len_monthDay_Username_b = ++monthDay_Username_b - (DstBuf + 1);
md5_monthDay_Username_b = (_DWORD *)md5_StrWithLength(DstBuf, monthDay_Username_b - (DstBuf + 1));// 2b28feebb48c0cb98b9f3da404fff646
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(
pThis,
"[HBKEY] mdata4: %s [%s]",
DstBuf,
md5_monthDay_Username_b);
md5_1 = 0;
md5_2 = 0;
md5_3 = 0;
md5_4 = 0;
if ( *(char *)(md5_bUsernameMonthDay + 1) % 2 )
{
md5_1 = md5_bUsernameMonthDay;
md5_2 = md5_username_MonthDay_b;
md5_3 = md5_username_b_MonthDay;
md5_4 = md5_monthDay_Username_b;
}
else
{
md5_1 = md5_bUsernameMonthDay;
md5_2 = md5_monthDay_Username_b;
md5_3 = md5_username_b_MonthDay;
md5_4 = md5_username_MonthDay_b;
}
hbKeyGa = 0;
memset(&mem_64_a, 0, 0x40u);
md5_1_pLus3remainder4 = *(char *)(md5_1 + 3) % 4;
// 以下一连串的赋值是使 char_array_29_1 = md5_1, char_array_29_2 = md5_2
char_array_29_1[0] = 0;
*(_DWORD *)&char_array_29_1[1] = 0;
*(_DWORD *)&char_array_29_1[5] = 0;
*(_DWORD *)&char_array_29_1[9] = 0;
*(_DWORD *)&char_array_29_1[13] = 0;
*(_DWORD *)&char_array_29_1[17] = 0;
*(_DWORD *)&char_array_29_1[21] = 0;
*(_DWORD *)&char_array_29_1[25] = 0;
v136 = 0;
v137 = 0;
char_array_29_2[0] = 0;
*(_DWORD *)&char_array_29_2[1] = 0;
*(_DWORD *)&char_array_29_2[5] = 0;
*(_DWORD *)&char_array_29_2[9] = 0;
*(_DWORD *)&char_array_29_2[13] = 0;
*(_DWORD *)&char_array_29_2[17] = 0;
*(_DWORD *)&char_array_29_2[21] = 0;
*(_DWORD *)&char_array_29_2[25] = 0;
v133 = 0;
v134 = 0;
*(_DWORD *)char_array_29_1 = *(_DWORD *)md5_1;
*(_DWORD *)&char_array_29_1[4] = *(_DWORD *)(md5_1 + 4);
*(_DWORD *)&char_array_29_1[8] = *(_DWORD *)(md5_1 + 8);
*(_DWORD *)&char_array_29_1[12] = *(_DWORD *)(md5_1 + 12);
*(_DWORD *)&char_array_29_1[16] = *(_DWORD *)(md5_1 + 16);
*(_DWORD *)&char_array_29_1[20] = *(_DWORD *)(md5_1 + 20);
*(_DWORD *)&char_array_29_1[24] = *(_DWORD *)(md5_1 + 24);
*(_DWORD *)&char_array_29_1[28] = *(_DWORD *)(md5_1 + 28);
*(_DWORD *)char_array_29_2 = *md5_2;
*(_DWORD *)&char_array_29_2[4] = md5_2[1];
*(_DWORD *)&char_array_29_2[8] = md5_2[2];
*(_DWORD *)&char_array_29_2[12] = md5_2[3];
*(_DWORD *)&char_array_29_2[16] = md5_2[4];
*(_DWORD *)&char_array_29_2[20] = md5_2[5];
*(_DWORD *)&char_array_29_2[24] = md5_2[6];
*(_DWORD *)&char_array_29_2[28] = md5_2[7];
v81 = md5_1_pLus3remainder4; // 0
v82 = abs(md5_1_pLus3remainder4 - 5) % 4; // 1
v8 = (md5_1_pLus3remainder4 + 2) % 4; // 2
v83 = (md5_1_pLus3remainder4 + 2) % 4; // 2
v84 = abs(md5_1_pLus3remainder4 - 3); // 3
v96[0] = 0;
*(_DWORD *)&v96[1] = 0;
*(_DWORD *)&v97[1] = 0;
v98 = 0;
v99 = 0;
v100 = 0;
v101 = 0;
v102 = 0;
v103 = 0;
v104 = 0;
v105[0] = 0;
*(_DWORD *)&v105[1] = 0;
*(_DWORD *)&v106[1] = 0;
v107 = 0;
v108 = 0;
v109 = 0;
v110 = 0;
v111 = 0;
v112 = 0;
v113 = 0;
*(_DWORD *)v96 = *(_DWORD *)&char_array_29_1[8 * md5_1_pLus3remainder4];
*(_DWORD *)v97 = *(_DWORD *)&char_array_29_1[8 * md5_1_pLus3remainder4 + 4];
*(_DWORD *)&v97[4] = *(_DWORD *)&char_array_29_2[8 * v82];
*(int *)((char *)&v98 + 3) = *(_DWORD *)&char_array_29_2[8 * v82 + 4];
*(int *)((char *)&v99 + 3) = *(_DWORD *)&char_array_29_1[8 * v8];
*(int *)((char *)&v100 + 3) = *(_DWORD *)&char_array_29_1[8 * v8 + 4];
*(int *)((char *)&v101 + 3) = *(_DWORD *)&char_array_29_2[8 * v84];
*(int *)((char *)&v102 + 3) = *(_DWORD *)&char_array_29_2[8 * v84 + 4];
*(_DWORD *)v105 = *(_DWORD *)&char_array_29_2[8 * md5_1_pLus3remainder4];
*(_DWORD *)v106 = *(_DWORD *)&char_array_29_2[8 * md5_1_pLus3remainder4 + 4];
*(_DWORD *)&v106[4] = *(_DWORD *)&char_array_29_1[8 * v82];
*(int *)((char *)&v107 + 3) = *(_DWORD *)&char_array_29_1[8 * v82 + 4];
*(int *)((char *)&v108 + 3) = *(_DWORD *)&char_array_29_2[8 * v8];
*(int *)((char *)&v109 + 3) = *(_DWORD *)&char_array_29_2[8 * v8 + 4];
*(int *)((char *)&v110 + 3) = *(_DWORD *)&char_array_29_1[8 * v84];
*(int *)((char *)&v111 + 3) = *(_DWORD *)&char_array_29_1[8 * v84 + 4];
mix_md5_1 = (void *)md5_StrWithLength(v96, 32);// 第一个参数 5e64fdaa43beed0eb9693f27e7fb624c6614da796449e2ab7baafc0b57c11652
// 返回值 5008ef506febfc228802dd43b99c1869
// 为 5e64fdaa43beed0eb9693f27e7fb624c 的 md5
mix_md5_2 = (void *)md5_StrWithLength(v105, 32);// 第一个参数 6614da796449e2ab7baafc0b57c11652
// 返回值 46e4a9da513469a20da82e3136f46951
sprintf_s(&hbKeyGa, 0x41u, "%s%s", mix_md5_1, mix_md5_2);// hbKeyGa = "5008ef506febfc228802dd43b99c186946e4a9da513469a20da82e3136f46951"
lp_mix_md5_1 = mix_md5_1;
j_j___free_base(mix_md5_1);
if ( lp_mix_md5_1 )
{
mix_md5_1 = (void *)33059;
v35 = 33059;
}
else
{
v35 = 0;
}
v44 = mix_md5_2;
j_j___free_base(mix_md5_2);
if ( v44 )
{
mix_md5_2 = (void *)33059;
v34 = 33059;
}
else
{
v34 = 0;
}
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, "[HBKEY] ga: %s", &hbKeyGa);
hbKeyGb = 0;
memset(&mem_64_b, 0, 0x40u);
md5_4_plus5remainer4 = *((char *)md5_4 + 5) % 4;
// 以下一连串的赋值是使 char_array_29_3 = md5_3, char_array_29_4 = md5_4
char_array_29_3[0] = 0;
*(_DWORD *)&char_array_29_3[1] = 0;
*(_DWORD *)&char_array_29_3[5] = 0;
*(_DWORD *)&char_array_29_3[9] = 0;
*(_DWORD *)&char_array_29_3[13] = 0;
*(_DWORD *)&char_array_29_3[17] = 0;
*(_DWORD *)&char_array_29_3[21] = 0;
*(_DWORD *)&char_array_29_3[25] = 0;
v139 = 0;
v140 = 0;
char_array_29_4[0] = 0;
*(_DWORD *)&char_array_29_4[1] = 0;
*(_DWORD *)&char_array_29_4[5] = 0;
*(_DWORD *)&char_array_29_4[9] = 0;
*(_DWORD *)&char_array_29_4[13] = 0;
*(_DWORD *)&char_array_29_4[17] = 0;
*(_DWORD *)&char_array_29_4[21] = 0;
*(_DWORD *)&char_array_29_4[25] = 0;
v142 = 0;
v143 = 0;
*(_DWORD *)char_array_29_3 = *md5_3;
*(_DWORD *)&char_array_29_3[4] = md5_3[1];
*(_DWORD *)&char_array_29_3[8] = md5_3[2];
*(_DWORD *)&char_array_29_3[12] = md5_3[3];
*(_DWORD *)&char_array_29_3[16] = md5_3[4];
*(_DWORD *)&char_array_29_3[20] = md5_3[5];
*(_DWORD *)&char_array_29_3[24] = md5_3[6];
*(_DWORD *)&char_array_29_3[28] = md5_3[7];
*(_DWORD *)char_array_29_4 = *md5_4;
*(_DWORD *)&char_array_29_4[4] = md5_4[1];
*(_DWORD *)&char_array_29_4[8] = md5_4[2];
*(_DWORD *)&char_array_29_4[12] = md5_4[3];
*(_DWORD *)&char_array_29_4[16] = md5_4[4];
*(_DWORD *)&char_array_29_4[20] = md5_4[5];
*(_DWORD *)&char_array_29_4[24] = md5_4[6];
*(_DWORD *)&char_array_29_4[28] = md5_4[7];
v85 = md5_4_plus5remainer4; // 1
v86 = abs(md5_4_plus5remainer4 - 5) % 4; // 0
v9 = (md5_4_plus5remainer4 + 2) % 4; // 3
v87 = (md5_4_plus5remainer4 + 2) % 4; // 3
v88 = abs(md5_4_plus5remainer4 - 3); // 2
v114[0] = 0;
*(_DWORD *)&v114[1] = 0;
*(_DWORD *)&v115[1] = 0;
v116 = 0;
v117 = 0;
v118 = 0;
v119 = 0;
v120 = 0;
v121 = 0;
v122 = 0;
v123[0] = 0;
*(_DWORD *)&v123[1] = 0;
*(_DWORD *)&v124[1] = 0;
v125 = 0;
v126 = 0;
v127 = 0;
v128 = 0;
v129 = 0;
v130 = 0;
v131 = 0;
*(_DWORD *)v114 = *(_DWORD *)&char_array_29_3[8 * md5_4_plus5remainer4];
*(_DWORD *)v115 = *(_DWORD *)&char_array_29_3[8 * md5_4_plus5remainer4 + 4];
*(_DWORD *)&v115[4] = *(_DWORD *)&char_array_29_4[8 * v86];
*(int *)((char *)&v116 + 3) = *(_DWORD *)&char_array_29_4[8 * v86 + 4];
*(int *)((char *)&v117 + 3) = *(_DWORD *)&char_array_29_3[8 * v9];
*(int *)((char *)&v118 + 3) = *(_DWORD *)&char_array_29_3[8 * v9 + 4];
*(int *)((char *)&v119 + 3) = *(_DWORD *)&char_array_29_4[8 * v88];
*(int *)((char *)&v120 + 3) = *(_DWORD *)&char_array_29_4[8 * v88 + 4];
*(_DWORD *)v123 = *(_DWORD *)&char_array_29_4[8 * md5_4_plus5remainer4];
*(_DWORD *)v124 = *(_DWORD *)&char_array_29_4[8 * md5_4_plus5remainer4 + 4];
*(_DWORD *)&v124[4] = *(_DWORD *)&char_array_29_3[8 * v86];
*(int *)((char *)&v125 + 3) = *(_DWORD *)&char_array_29_3[8 * v86 + 4];
*(int *)((char *)&v126 + 3) = *(_DWORD *)&char_array_29_4[8 * v9];
*(int *)((char *)&v127 + 3) = *(_DWORD *)&char_array_29_4[8 * v9 + 4];
*(int *)((char *)&v128 + 3) = *(_DWORD *)&char_array_29_3[8 * v88];
*(int *)((char *)&v129 + 3) = *(_DWORD *)&char_array_29_3[8 * v88 + 4];
v58 = (void *)md5_StrWithLength(v114, 32); // 返回值 1ed63dc9a269d8705e297c03dcda7cf0
// 为 6172e2fb2b28feeb02bfb5a58b9f3da4 的 md5
v57 = (void *)md5_StrWithLength(v123, 32); // 返回值 25928da86463ce9beba8110d2d514464
// 为 b48c0cb916dffe4904fff6461bdb9b20 的 md5
sprintf_s(&hbKeyGb, 0x41u, "%s%s", v58, v57); // hbKeyGb = "1ed63dc9a269d8705e297c03dcda7cf025928da86463ce9beba8110d2d514464"
v43 = v58;
j_j___free_base(v58);
if ( v43 )
{
v58 = (void *)33059;
v22 = 33059;
}
else
{
v22 = 0;
}
v42 = v57;
j_j___free_base(v57);
if ( v42 )
{
v57 = (void *)33059;
v32 = 33059;
}
else
{
v32 = 0;
}
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, "[HBKEY] gb: %s", &hbKeyGb);
if ( v95 % 2 ) // 从反汇编中可看到 v95 为 hbkey_gb[7]
{
temp1 = 0;
p_HbKeyGa = &hbKeyGa;
pMem_64_a = &mem_64_a;
p_HbKeyGa += strlen(p_HbKeyGa);
lenHbKeyGa = ++p_HbKeyGa - &mem_64_a;
len_HbKeyGa = p_HbKeyGa - &mem_64_a;
while ( temp1 < len_HbKeyGa ) // 把 HbKeyGa 里面的小写字母全替换为大写
{
if ( *(&hbKeyGa + temp1) >= 97 && *(&hbKeyGa + temp1) <= 122 )
*(&hbKeyGa + temp1) -= 32;
++temp1;
}
}
else
{
temp2 = 0;
p_HbKeyGb = &hbKeyGb;
pMem_64_b = &mem_64_b;
p_HbKeyGb += strlen(p_HbKeyGb);
lenHbKeyGb = ++p_HbKeyGb - &mem_64_b;
len_HbKeyGb = p_HbKeyGb - &mem_64_b;
while ( temp2 < len_HbKeyGb ) // 把 HbKeyGb 里面的小写字母全替换为大写
{
if ( *(&hbKeyGb + temp2) >= 97 && *(&hbKeyGb + temp2) <= 122 )
*(&hbKeyGb + temp2) -= 32;
++temp2;
}
}
pHbKeyGa = &hbKeyGa;
pHbKeyGb = &hbKeyGb;
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, "[HBKEY] sga: %s", &hbKeyGa);
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, "[HBKEY] sgb: %s", pHbKeyGb);
hbKey = 0;
memset(&v90, 0, 0x80u);
if ( pHbKeyGb[9] % 2 )
{
index1 = 0;
index2 = 0;
index3 = 63;
while ( index1 < 128 )
{
*(&hbKey + index1++) = pHbKeyGa[index2++];
*(&hbKey + index1++) = pHbKeyGb[index3--];
}
}
else
{
index4 = 0;
index5 = 63;
index6 = 0;
while ( index4 < 128 )
{
*(&hbKey + index4++) = pHbKeyGa[index5--];
*(&hbKey + index4++) = pHbKeyGb[index6++];
}
}
(*(void (**)(char *, const char *, ...))(*(_DWORD *)pThis + 4))(pThis, "[HBKEY] key: %s", &hbKey);// hbKey = &"115e9d6643Fd6c391a32E6298dA8D70025Ae9269473c1053AdDc9dAa47Ec6f4092658912C89d9aB83644D6D32c0e898b2e2bCaF8B1E1F06d025dF5E184040654"
sub_40EC40((void *)a2, &hbKey);
v41 |= 1u;
v146 = -1;
std::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string<char,std::char_traits<char>,std::allocator<char>>(&a3);
return a2;
}
上面的就是 AidcRes.generateKey 的整个流程,这个坑多并且复杂,简要说一下,具体看代码(b_Username_MonthDay 代指 'b177111122220517',不再赘述)
1. 算出 b_Username_MonthDay,username_b_MonthDay,username_MonthDay_b,monthDay_Username_b 四个东西的 md5
2. 根据 d5_b_Username_MonthDay[1] 的 ascii的奇偶性,重排四个 md5 的顺序并复制给四个变量,分别为 md5_1,md5_2,md5_3,md5_4,
3. 此时会用到第二步的四个变量,根据他们的特定位来计算得出 hbkey_ga 与 hbkey_gb 的值
- 根据 md5_1_pLus3remainder4 = *(char *)(md5_1 + 3) % 4;
这步的值取 md5_1 和 md5_2 排列算出 hbkey_ga
- 根据 md5_4_plus5remainer4 = *((char *)md5_4 + 5) % 4;
这步的值取 md5_3 和 md5_4 排列算出 hbkey_gb
4. 根据 hbkey_gb[7] 的 ascii,如果奇数就把 hbkey_ga 中的字母都大写,偶数就把 hbkey_gb 中的字母都大写
5. 根据 hbkey_gb[9] 的 ascii 的奇偶性对 hbkey_ga 与 hbkey_gb 的值用简单算法进行重排,得到真实的 hbkey
这就是上面所有代码的大致流程,代码中我也有大量注释,大家可以看看。
0x03 总结
这个难点在分析算法上面,分析算法主要还是要靠动态调试,过程中遇到了很多很难的地方,参数和函数的重命名主要还是靠动态调试,
然后去猜测它的作用进行重命名。
这些文件我都保存了分析记录,大家可以跟着看看,总结如下
AidcComm.idb 看导出表可以看出是干嘛的,直接点进GetPWD即可看到我的分析
AidcRes.idb 里面也有我的分析,具体查看我改过的函数名 generateKey,然后 x 一下看调用地方
x32dbg_AidcRes.dd32 为我在用 x32dbg 分析AidcRes.exe的时候的记录,有一些我改过的函数名以及简要分析
简单的分析流程为 bp LoadLibrary,断到 AidcComm.dll,然后具体看eax和栈的变化,找到加密函数,再一层一层分析。
建议 ida 与 x32dbg 结合分析,最好起个 pppoe 服务器拦截账号密码协助分析,见我上一篇文章 PPPoE中间人拦截以及校园网突破漫谈中的代码。
调用流程为
AidcRes.generateKey(分析大头) --> AidcComm.GetRegularAccount --> AidcComm.GetPWD --> AidcComm.encryptPwdWithKey(分析大头,注意里面有个地方 f5 显示不出来,就是把一个key中的字母全大写的那部分,请结合汇编分析)
AidcRes.generateKey大致流程,这个坑多并且复杂,简要说一下,具体看代码
(b_Username_MonthDay 代指 'b177111122220517',不再赘述)
1. 算出 b_Username_MonthDay,username_b_MonthDay,username_MonthDay_b,monthDay_Username_b 四个东西的 md5
2. 根据 d5_b_Username_MonthDay[1] 的 ascii的奇偶性,重排四个 md5 的顺序并复制给四个变量
3. 此时会用到第二步的四个变量,根据他们的特定位来计算得出 hbkey_ga 与 hbkey_gb 的值
4. 根据 hbkey_gb[7] 的 ascii,如果奇数就把 hbkey_ga 中的字母都大写,偶数就把 hbkey_gb 中的字母都大写
5. 根据 hbkey_gb[9] 的 ascii 的奇偶性对 hbkey_ga 与 hbkey_gb 的值用简单算法进行重排,得到真实的 hbkey
AidcComm.encryptPwdWithKey大致流程
1. password 用 key RC4 一下得到 A
2. 把 A md5 一下得到 B,如果第 11 位为奇数,取 B 的前 16 位,偶数就后 16 位,得到 C
3. C 再用 key RC4 一下得到 D
4. D 再 md5 一下,取 [8:24]得到 E
5. E[今天几号日期 % 16] 替换为 'b' 得到最后的密码
为了防止被人商业利用,就不公布逆向写出来的加密脚本了。喜欢折腾校园网的可以根据本文自行摸索。