首页
社区
课程
招聘
[原创]看雪 CTF2018 第二题 TrieTree字典树基本结构
发表于: 2018-6-19 11:50 3550

[原创]看雪 CTF2018 第二题 TrieTree字典树基本结构

HHHso 活跃值
22
2018-6-19 11:50
3550
0x00 粗测
执行样例,随便输出,提示"Answer is Wrong"
IDA静态分析,View>Open Subviews>String窗,找不"Answer is Wrong"或其他类似"success"信息



0x01 按图索骥
由start,进入main函数,如下
.text:0040443C push    eax ; envp
.text:0040443D push    dword ptr [edi] ; argv
.text:0040443F push    dword ptr [esi] ; argc
.text:00404441 call   _main

再main开头,由"%s"和console UI操作,猜定Hi_scanf_sub_401170
.text:00402230 push    20h
.text:00402232 lea     eax, [ebp+loc_inputkey]
.text:00402235 push    eax
.text:00402236 push    offset aS ; "%s"
.text:0040223B call    Hi_scanf_sub_401170

进一步,我们逆向得到
Hi_get_OK_msg_sub_401360 获取该函数内置数据解密出的提示信息"Answer correct!"
Hi_get_NO_msg_sub_401200 获取该函数内置数据解密出的提示信息"Answer is Wrong"
Hi_Is_AZaz09_sub_402180  判断输出loc_inputkey是否为限制于A-Za-z0-9
输入的inputkey长度要求为22个字符,卖弄函数主要逻辑如下
int __cdecl main(int argc,const char**argv,const char**envp)
{
  int result;// eax
  char loc_inputkey[32];// [esp+10h] [ebp-44h]
  char loc_i16_1_OK[16];// [esp+30h] [ebp-24h]
  char loc_i16_2_NO[16];// [esp+40h] [ebp-14h]

  Hi_scanf_sub_401170("%s",loc_inputkey,32);
  Hi_get_OK_msg_sub_401360(loc_i16_1_OK);//Answer correct!
  Hi_get_NO_msg_sub_401200(loc_i16_2_NO);//Answer is Wrong
  if(Hi_Is_AZaz09_sub_402180(loc_inputkey,(int)loc_i16_2_NO))
  {
    if(&loc_inputkey[strlen(loc_inputkey)+1]-&loc_inputkey[1]==22)
      Hi_check_key_sub_401C40(loc_inputkey,(int)loc_i16_1_OK,(int)loc_i16_2_NO);
    else
      Hi_printf_sub_4011D0(loc_i16_2_NO);
    //clear loc_i16_2_NO loc_i16_1_OK
    system("pause");
    result=0;
  }
  else
  {
    //clear loc_i16_2_NO loc_i16_1_OK
    result=0;
  }
}

在Hi_Is_AZaz09_sub_402180中,
通过Hi_is_AZ_az_sub_402140 和 Hi_is_09_sub_402110对输入key分别检测大小写字母与数字,如下
若错误,显示错误信息loc_i16_2_NO);//Answer is Wrong
char __cdecl Hi_Is_AZaz09_sub_402180(const char*a1,int a2)
{
  signed int loc_keylen;// kr00_4
  signed int loc_i;// [esp+Ch] [ebp-Ch]

  loc_keylen=strlen(a1);
  for(loc_i=0;loc_i<loc_keylen;++loc_i)
  {
    if(!Hi_is_AZ_az_sub_402140(a1[loc_i])&&!Hi_is_09_sub_402110(a1[loc_i]))
    {
      Hi_printf_sub_4011D0(a2);
      return 0;
    }
  }
  return 1;
}

0x03 在上述main中得到key校验函数
Hi_check_key_sub_401C40(loc_inputkey,(int)loc_i16_1_OK,(int)loc_i16_2_NO);
其主要业务逻辑是
(1)将input_key分成八个部分(产生八个字典字),
(2)将字添加到字典树中,与参考字典树比对(完成第一步检验)
(3)若通过(2)的检验,则由Hi_last_check_sub_401B80进一步对其中四个字进行限制检验
(*)若(2)或(3)都检验成功,则输出成功提示loc_i16_1_OK  //Answer correct!
   若不匹配,则输出错误提示            loc_i16_2_NO  //Answer is Wrong

int __cdecl Hi_check_key_sub_401C40(char*P1_inputkey,int P2_OK,int P3_Err)
{
  char v4;// [esp+4h] [ebp-47Ch]
  char v5;// [esp+88h] [ebp-3F8h]
  char v6;// [esp+10Ch] [ebp-374h]
  char v7;// [esp+190h] [ebp-2F0h]
  char v8;// [esp+214h] [ebp-26Ch]
  char v9;// [esp+298h] [ebp-1E8h]
  szWord v10;// [esp+31Ch] [ebp-164h]
  szWord loc_szword_kdef;// [esp+3A0h] [ebp-E0h]
  int v12;// [esp+424h] [ebp-5Ch]
  int v13;// [esp+428h] [ebp-58h]
  int v14;// [esp+42Ch] [ebp-54h]
  int v15;// [esp+430h] [ebp-50h]
  int v16;// [esp+434h] [ebp-4Ch]
  int v17;// [esp+438h] [ebp-48h]
  int v18;// [esp+43Ch] [ebp-44h]
  int v19;// [esp+440h] [ebp-40h]
  char loc_k131415[4];// [esp+444h] [ebp-3Ch]
  char loc_k456[4];// [esp+448h] [ebp-38h]
  char loc_k23[3];// [esp+44Ch] [ebp-34h]
  char loc_kdef[4];// [esp+450h] [ebp-30h]
  char loc_k101112[4];// [esp+454h] [ebp-2Ch]
  int loc_TrieTree[2];// [esp+458h] [ebp-28h]
  char loc_k01[3];// [esp+460h] [ebp-20h]
  char loc_k78[3];// [esp+464h] [ebp-1Ch]
  char loc_k9abc[5];// [esp+468h] [ebp-18h]
  int v29;// [esp+47Ch] [ebp-4h]

  v19=2;
  loc_k01[2]=0;
  loc_k23[0]=P1_inputkey[2];
  v18=3;
  loc_k456[3]=0;
  loc_k01[1]=P1_inputkey[1];
  loc_k9abc[3]=P1_inputkey[12];
  loc_k101112[0]=P1_inputkey[16];
  loc_k9abc[0]=P1_inputkey[9];
  loc_k78[0]=P1_inputkey[7];
  loc_k9abc[1]=P1_inputkey[10];
  loc_k78[1]=P1_inputkey[8];
  loc_k131415[1]=P1_inputkey[20];
  v17=4;
  loc_k9abc[4]=0;
  loc_kdef[2]=P1_inputkey[15];
  v16=2;
  loc_k23[2]=0;
  v15=2;
  loc_k78[2]=0;
  loc_k456[2]=P1_inputkey[6];
  loc_kdef[1]=P1_inputkey[14];
  loc_k456[0]=P1_inputkey[4];
  loc_k23[1]=P1_inputkey[3];
  loc_kdef[0]=P1_inputkey[13];
  v14=3;
  loc_k101112[3]=0;
  loc_k456[1]=P1_inputkey[5];
  loc_k101112[1]=P1_inputkey[17];
  loc_k01[0]=*P1_inputkey;
  loc_k131415[2]=P1_inputkey[21];
  v13=3;
  loc_kdef[3]=0;
  loc_k131415[0]=P1_inputkey[19];
  loc_k9abc[2]=P1_inputkey[11];
  loc_k101112[2]=P1_inputkey[18];
  v12=3;
  loc_k131415[3]=0;
  loc_TrieTree[0]=0;
  loc_TrieTree[1]=0;
  std::_Ref_count_obj<__ExceptionPtr>::_Ref_count_obj<__ExceptionPtr>(loc_TrieTree);
  v29=0;
  Hi_TTWord_asign_sub_403AB0(loc_szword_kdef.data,loc_kdef);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&loc_szword_kdef);
  Hi_TTWord_asign_sub_403AB0(v10.data,loc_k01);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v10);
  Hi_TTWord_asign_sub_403AB0(&v9,loc_k9abc);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v9);
  Hi_TTWord_asign_sub_403AB0(&v8,loc_k456);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v8);
  Hi_TTWord_asign_sub_403AB0(&v7,loc_k23);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v7);
  Hi_TTWord_asign_sub_403AB0(&v6,loc_k78);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v6);
  Hi_TTWord_asign_sub_403AB0(&v5,loc_k101112);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v5);
  Hi_TTWord_asign_sub_403AB0(&v4,loc_k131415);
  Hi_TT_add_TTNszw_sub_402B40(loc_TrieTree,(int)&v4);
  if((unsigned __int8)Hi_TT_cmp_sub_4030E0(loc_TrieTree,(int)&Hi_RefTT_dword_407E48))
    Hi_last_check_sub_401B80(loc_k01,loc_k78,(int)loc_kdef,(int)loc_k101112,P2_OK,P3_Err);
  else
    Hi_printf_sub_4011D0(P3_Err);
  v29=-1;
  return Hi_TT_dtor_sub_402AC0((void(__thiscall****)(_DWORD,signed int))loc_TrieTree);
}


0x04 字典树基本结构
字典树的字串TTWord,字典树TrieTree,字典树字结点TrieTreeNode相关类型和内存结构如下定义
class TrieTree;
class TrieTreeNode;
typedef struct _TTWord{//cbSize:0x84
  /* .00  */ char szword[0x80];             //字典字串的字符串数据
  /* .80  */ unsigned int length;           //字典字串的字符串长度
} TTWord,*PTTWord;
typedef struct _TrieTreeNodeList{
  /* .00  */ TrieTreeNode* TTNBuffer[0x20];  //字典字结点的子字结点(分支结点)数组
  /* .80  */ unsigned int TTNCount;          //字典字结点的子字结点(分支结点)数组元素个数
} TrieTreeNodeList,*PTrieTreeNodeList;

class TrieTreeNode{//cbSize:0x110
  /* .00  */ //vft.TrieTreeNode :: vft.TrieTreeNodeAbs
  /* .04  */ TTWord ttword;                     //字结点 表示的 字串
  /* .88  */ TrieTreeNodeList subTTNList;       //字结点 的 子-字结点
  /* .10C */ unsigned int Count;                //字节点出现次数,表示其代表的 字串 出现次数
}
class TrieTree{//cbSize:0x08
  /* .00  */ //vft.TrieTree :: vft.TrieTreeAbs
  /* .04  */ TrieTreeNode root;                  //字典树  根字结点开始索引  一般 root.ttword.szword==""
}

0x05 input_key的字分割
前面分析可知input_key 长度为 22 (0x16),即char input_key[0x16];下标索引从0到0x15,

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

收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
为什么我的start点进去的函数地址不对呀
text:004044BC                                  public  start
.text:004044BC  start                      proc  near
.text:004044BC
.text:004044BC  ;  FUNCTION  CHUNK  AT  .text:0040434D  SIZE  0000012C  BYTES
.text:004044BC  ;  FUNCTION  CHUNK  AT  .text:004044B6  SIZE  00000006  BYTES
.text:004044BC
.text:004044BC                                  call        sub_4049CA
.text:004044C1                                  jmp          loc_40434D
.text:004044C1  start                      endp  ;  sp-analysis  failed

这是怎么回事,粗了什么问题?
2018-6-23 20:50
0
游客
登录 | 注册 方可回帖
返回
//