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直播授课