首页
社区
课程
招聘
[原创]KCTF Q3 第二题:血肉佣兵
发表于: 2019-9-24 02:29 5671

[原创]KCTF Q3 第二题:血肉佣兵

2019-9-24 02:29
5671

之前比赛有出现的类似题目,但是这次虚拟执行的部分强化了很多,我并没有分析出虚拟执行的部分,有点遗憾。

用OD从内存中dump出完整的html。内存搜索 unicode "CTF 2019"就能找到了。

为了方便调试,可以把script标签里面的代码另存为一个js文件。

得到解密后的js代码,这里为了方便看,就把两个function放到一起了。
function sptWBCallback(spt_wb_id, spt_wb_name, optionstr) {
    url = '#sptWBCallback:id=';
    url = url + spt_wb_id + ';eventName=' + spt_wb_name;
    if (optionstr)
        url = url + ';params=optionstr';
    location = url;
}
function ckpswd() {
    key = "Simpower91";
    a = document.all.pswd.value;
    if (a.indexOf(key) == 0) {
        l = a.length;
        i = key.length;
        sptWBCallback(a.substring(i, l));
    } else {
        alert("wrong!<" + a + "> is not my GUID ;-)");
        return "1234";
    }
}
function ok() {
    alert("congratulations!");
}
得到flag前面的部分为"Simpower91"。
然后我们需要找到回调函数,先用IDR分析CM,导出MAP,给IDA使用(需要插件)。
int __fastcall Unit1_Tfrmcrackme_FormCreate(int a1)
{
  int v1; // ebx
  int v2; // edx
  int v3; // eax
  int v4; // eax
  double v5; // ST00_8
  int v6; // edx
  int v7; // ecx
  int v8; // edx
  int v9; // eax
  int v10; // edx
  int v11; // edx
  Teengine::TTeeFunction *v12; // eax
  double v13; // ST00_8
  int v14; // edx
  int result; // eax
  unsigned int v16; // [esp-Ch] [ebp-14h]
  void *v17; // [esp-8h] [ebp-10h]
  int *v18; // [esp-4h] [ebp-Ch]
  int savedregs; // [esp+8h] [ebp+0h]

  v1 = a1;
  v18 = &savedregs;
  v17 = &loc_498D75;
  v16 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v16);
  SHDocVw_TWebBrowser_Navigate(*(Shdocvw::TWebBrowser **)(a1 + 760));
  LOBYTE(v2) = 1;
  dword_49DF50 = Unit87_TVirtualMachine_Create("\x0FTVirtualMachine", v2);
  v3 = dword_49DF50;
  *(_DWORD *)(dword_49DF50 + 4372) = dword_49DF50;
  *(_DWORD *)(v3 + 4368) = sub_477514;
  v4 = ScripertJava_TScripertJava_Create((Classes::TComponent *)&cls_ScripertJava_TScripertJava);
  *(_DWORD *)(v1 + 824) = v4;
  *(_DWORD *)(v4 + 72) = *(_DWORD *)(v1 + 760);
  sub_4969C0(v4);
  HIDWORD(v5) = v1;
  LODWORD(v5) = &sub_49945C;                    // 回调函数
  ScripertJava_TScripertJava_SetOnSptWBCallBack(*(Teengine::TTeeFunction **)(v1 + 824), v5);// 设置回调函数
  ScripertJava_TScripertJava_SetOnBeforeSptWBCallBack(*(_DWORD *)(v1 + 824), v6, v7, v1, (int)sub_499428);
  LOBYTE(v8) = 1;
  v9 = Unit91_TIHookAgent_Create(dword_4957E8, v8);
  *(_DWORD *)(v1 + 832) = v9;
  Iddnsserver::TIdDNTreeNode::SaveToFile(v9, 0);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), antiDebug_kernel32_IsDebuggerPresent, &str_idp[1]);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), MessageBoxW, &str_mb[1]);
  LOBYTE(v10) = 1;
  *(_DWORD *)(v1 + 820) = system_TObject_Create(dword_46F088, v10);
  LOBYTE(v11) = 1;
  v12 = (Teengine::TTeeFunction *)antiDebug_TAntiDebug_Create(&cls_antiDebug_TAntiDebug, v11, 0);
  *(_DWORD *)(v1 + 828) = v12;
  HIDWORD(v13) = v1;
  LODWORD(v13) = sub_49978C;
  antiDebug_TAntiDebug_SetOnCheckTrue(v12, v13);
  antiDebug_TAntiDebug_SetOnAllCheckFalse(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14);
  dword_49DF54 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 0);
  dword_49DF58 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 1);
  *(_BYTE *)(v1 + 836) = 0;
  result = 0;
  __writefsdword(0, v16);
  return result;
}
在Unit1_Tfrmcrackme_FormCreate事件里面能看到设置的回调函数sub_49978C。因为不能使用F5,后面还是用OD动态调试,同样可以把map导入到OD。
OD载入CM(带SharpOD插件过反调试),0049978C 下断,输入 "Simpower911",点击按钮。
用处理异常的方法来跳转,单步过去。

单步出retn。



跟进call。

单步过第一个call没有问题,过第二个call时跑飞了,在单步过第一个call时,查看堆栈上面,发现一个可疑的调用。

00404734 strlen,在运行到004777E2处时对其下断。
运行到00476B8C,用OD的跟踪步过看看发生了什么。

在00476C3E处跑飞,可以在这里下断,测试一下几次后跑飞,然后在跑飞之前用跟踪步入,等OD断在strlen处。
在这条retn指令下断,继续运行。

eax出现 Simpower91后面的字符串的长度,继续单步,发现走出了回调函数。
有可能是字符串的长度不符合,然后就直接返回了,增加字符串的字数,继续测试几次,输入 “Simpower911111”的时候,寄存器的值发生明显变化了。

eax与edx较可疑,把输入后面改成2222发现eax是字符的ascii值加0x7F,那edx应该就是flag的ascii加0x7F了。
根据edx修改输入,edx的值分别为0xE0, 0xB2, 0xB1, 0xB0,最终得到flag后四位为a321。
故flag为:
Simpower91a321

为了方便调试,可以把script标签里面的代码另存为一个js文件。

得到解密后的js代码,这里为了方便看,就把两个function放到一起了。
function sptWBCallback(spt_wb_id, spt_wb_name, optionstr) {
    url = '#sptWBCallback:id=';
    url = url + spt_wb_id + ';eventName=' + spt_wb_name;
    if (optionstr)
        url = url + ';params=optionstr';
    location = url;
}
function ckpswd() {
    key = "Simpower91";
    a = document.all.pswd.value;
    if (a.indexOf(key) == 0) {
        l = a.length;
        i = key.length;
        sptWBCallback(a.substring(i, l));
    } else {
        alert("wrong!<" + a + "> is not my GUID ;-)");
        return "1234";
    }
}
function ok() {
    alert("congratulations!");
}
得到flag前面的部分为"Simpower91"。
function sptWBCallback(spt_wb_id, spt_wb_name, optionstr) {
    url = '#sptWBCallback:id=';
    url = url + spt_wb_id + ';eventName=' + spt_wb_name;
    if (optionstr)
        url = url + ';params=optionstr';
    location = url;
}
function ckpswd() {
    key = "Simpower91";
    a = document.all.pswd.value;
    if (a.indexOf(key) == 0) {
        l = a.length;
        i = key.length;
        sptWBCallback(a.substring(i, l));
    } else {
        alert("wrong!<" + a + "> is not my GUID ;-)");
        return "1234";
    }
}
function ok() {
    alert("congratulations!");
}
得到flag前面的部分为"Simpower91"。
然后我们需要找到回调函数,先用IDR分析CM,导出MAP,给IDA使用(需要插件)。
int __fastcall Unit1_Tfrmcrackme_FormCreate(int a1)
{
  int v1; // ebx
  int v2; // edx
  int v3; // eax
  int v4; // eax
  double v5; // ST00_8
  int v6; // edx
  int v7; // ecx
  int v8; // edx
  int v9; // eax
  int v10; // edx
  int v11; // edx
  Teengine::TTeeFunction *v12; // eax
  double v13; // ST00_8
  int v14; // edx
  int result; // eax
  unsigned int v16; // [esp-Ch] [ebp-14h]
  void *v17; // [esp-8h] [ebp-10h]
  int *v18; // [esp-4h] [ebp-Ch]
  int savedregs; // [esp+8h] [ebp+0h]

  v1 = a1;
  v18 = &savedregs;
  v17 = &loc_498D75;
  v16 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v16);
  SHDocVw_TWebBrowser_Navigate(*(Shdocvw::TWebBrowser **)(a1 + 760));
  LOBYTE(v2) = 1;
  dword_49DF50 = Unit87_TVirtualMachine_Create("\x0FTVirtualMachine", v2);
  v3 = dword_49DF50;
  *(_DWORD *)(dword_49DF50 + 4372) = dword_49DF50;
  *(_DWORD *)(v3 + 4368) = sub_477514;
  v4 = ScripertJava_TScripertJava_Create((Classes::TComponent *)&cls_ScripertJava_TScripertJava);
  *(_DWORD *)(v1 + 824) = v4;
  *(_DWORD *)(v4 + 72) = *(_DWORD *)(v1 + 760);
  sub_4969C0(v4);
  HIDWORD(v5) = v1;
  LODWORD(v5) = &sub_49945C;                    // 回调函数
  ScripertJava_TScripertJava_SetOnSptWBCallBack(*(Teengine::TTeeFunction **)(v1 + 824), v5);// 设置回调函数
  ScripertJava_TScripertJava_SetOnBeforeSptWBCallBack(*(_DWORD *)(v1 + 824), v6, v7, v1, (int)sub_499428);
  LOBYTE(v8) = 1;
  v9 = Unit91_TIHookAgent_Create(dword_4957E8, v8);
  *(_DWORD *)(v1 + 832) = v9;
  Iddnsserver::TIdDNTreeNode::SaveToFile(v9, 0);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), antiDebug_kernel32_IsDebuggerPresent, &str_idp[1]);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), MessageBoxW, &str_mb[1]);
  LOBYTE(v10) = 1;
  *(_DWORD *)(v1 + 820) = system_TObject_Create(dword_46F088, v10);
  LOBYTE(v11) = 1;
  v12 = (Teengine::TTeeFunction *)antiDebug_TAntiDebug_Create(&cls_antiDebug_TAntiDebug, v11, 0);
  *(_DWORD *)(v1 + 828) = v12;
  HIDWORD(v13) = v1;
  LODWORD(v13) = sub_49978C;
  antiDebug_TAntiDebug_SetOnCheckTrue(v12, v13);
  antiDebug_TAntiDebug_SetOnAllCheckFalse(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14);
  dword_49DF54 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 0);
  dword_49DF58 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 1);
  *(_BYTE *)(v1 + 836) = 0;
  result = 0;
  __writefsdword(0, v16);
  return result;
}
在Unit1_Tfrmcrackme_FormCreate事件里面能看到设置的回调函数sub_49978C。因为不能使用F5,后面还是用OD动态调试,同样可以把map导入到OD。
int __fastcall Unit1_Tfrmcrackme_FormCreate(int a1)
{
  int v1; // ebx
  int v2; // edx
  int v3; // eax
  int v4; // eax
  double v5; // ST00_8
  int v6; // edx
  int v7; // ecx
  int v8; // edx
  int v9; // eax
  int v10; // edx
  int v11; // edx
  Teengine::TTeeFunction *v12; // eax
  double v13; // ST00_8
  int v14; // edx
  int result; // eax
  unsigned int v16; // [esp-Ch] [ebp-14h]
  void *v17; // [esp-8h] [ebp-10h]
  int *v18; // [esp-4h] [ebp-Ch]
  int savedregs; // [esp+8h] [ebp+0h]

  v1 = a1;
  v18 = &savedregs;
  v17 = &loc_498D75;
  v16 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v16);
  SHDocVw_TWebBrowser_Navigate(*(Shdocvw::TWebBrowser **)(a1 + 760));
  LOBYTE(v2) = 1;
  dword_49DF50 = Unit87_TVirtualMachine_Create("\x0FTVirtualMachine", v2);
  v3 = dword_49DF50;
  *(_DWORD *)(dword_49DF50 + 4372) = dword_49DF50;
  *(_DWORD *)(v3 + 4368) = sub_477514;
  v4 = ScripertJava_TScripertJava_Create((Classes::TComponent *)&cls_ScripertJava_TScripertJava);
  *(_DWORD *)(v1 + 824) = v4;
  *(_DWORD *)(v4 + 72) = *(_DWORD *)(v1 + 760);
  sub_4969C0(v4);
  HIDWORD(v5) = v1;
  LODWORD(v5) = &sub_49945C;                    // 回调函数
  ScripertJava_TScripertJava_SetOnSptWBCallBack(*(Teengine::TTeeFunction **)(v1 + 824), v5);// 设置回调函数
  ScripertJava_TScripertJava_SetOnBeforeSptWBCallBack(*(_DWORD *)(v1 + 824), v6, v7, v1, (int)sub_499428);
  LOBYTE(v8) = 1;
  v9 = Unit91_TIHookAgent_Create(dword_4957E8, v8);
  *(_DWORD *)(v1 + 832) = v9;
  Iddnsserver::TIdDNTreeNode::SaveToFile(v9, 0);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), antiDebug_kernel32_IsDebuggerPresent, &str_idp[1]);
  sub_494694(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), MessageBoxW, &str_mb[1]);
  LOBYTE(v10) = 1;
  *(_DWORD *)(v1 + 820) = system_TObject_Create(dword_46F088, v10);
  LOBYTE(v11) = 1;
  v12 = (Teengine::TTeeFunction *)antiDebug_TAntiDebug_Create(&cls_antiDebug_TAntiDebug, v11, 0);
  *(_DWORD *)(v1 + 828) = v12;
  HIDWORD(v13) = v1;
  LODWORD(v13) = sub_49978C;
  antiDebug_TAntiDebug_SetOnCheckTrue(v12, v13);
  antiDebug_TAntiDebug_SetOnAllCheckFalse(*(Idsyslogmessage::TIdSysLogMessage **)(v1 + 828), v14);
  dword_49DF54 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 0);
  dword_49DF58 = sub_494898(*(_DWORD *)(*(_DWORD *)(v1 + 832) + 24), 1);
  *(_BYTE *)(v1 + 836) = 0;
  result = 0;
  __writefsdword(0, v16);
  return result;
}
在Unit1_Tfrmcrackme_FormCreate事件里面能看到设置的回调函数sub_49978C。因为不能使用F5,后面还是用OD动态调试,同样可以把map导入到OD。
OD载入CM(带SharpOD插件过反调试),0049978C 下断,输入 "Simpower911",点击按钮。
用处理异常的方法来跳转,单步过去。

单步出retn。




[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-9-25 18:22 被梦游枪手编辑 ,原因: 补第一张图
上传的附件:
收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 5189
活跃值: (9712)
能力值: ( LV9,RANK:181 )
在线值:
发帖
回帖
粉丝
2
在OD里怎么搞定:External exception 80000003 这个弹框 ?
2019-9-25 16:01
0
雪    币: 2155
活跃值: (2592)
能力值: ( LV12,RANK:667 )
在线值:
发帖
回帖
粉丝
3
nevinhappy 在OD里怎么搞定:External exception 80000003 这个弹框 ?
反调试部分我用sharpOD插件处理掉就没问题了。
2019-9-25 18:18
0
游客
登录 | 注册 方可回帖
返回
//