0x01
签到题,下载,压缩,拖进IDA,查阅"String"
由"success!\n" xref交叉引用到关键业务逻辑,位于main函数处
留意到开头处,复制
"437261636b4d654a757374466f7246756e"提交,错误;
审阅代码逻辑,长度不超过0x11,输入key字符经格式化"%x"转十六进制后再比对上述key,则
通过以下脚本得到输入key
>>> a="437261636b4d654a757374466f7246756e"
>>> for i in xrange(0,a.__len__(),2):
... print chr(int(a[i:i+2],16)),
...
C r a c k M e J u s t F o r F u n
>>> 'C r a c k M e J u s t F o r F u n'.replace(' ','')
'CrackMeJustForFun'
复制提交,提示成功。
提炼脚本为
cmpInnerHexKey = "437261636b4d654a757374466f7246756e"
b''.join([chr(int(
cmpInnerHexKey
[i:i+2],16)) for i in xrange(0,
cmpInnerHexKey
.__len__(),2)])
0x02
如何从汇编逻辑与栈布局揣度作者源代码布局等其它信息?
下述为根据main函数堆栈布局逆推的源码,
通过VC6.0 编译器 cl.exe 的 /O2 优化开关可以得到几乎一模一样的二进制业务逻辑。
//vc98\bin\vcvars32.bat
//kxctf.c
//to compile: cl /O2 kxctf.c
#include <windows.h>
void main(int argc,char* argv){
char szInnerHexKey[36]="437261636b4d654a757374466f7246756e";
char szInputHexKey[36];
char szInputKey[20];
char szHexKeyCh[2];
int i;
char Ch;
while(1){
printf("please input your serial:");
scanf("%s",szInputKey);
if(strlen(szInputKey)>0x11){
printf("wrong!\n");
getchar();
return;
}
for( i=0;i<0x11;i++){
Ch = szInputKey[i];
if(Ch==0){
break;
}
sprintf(szHexKeyCh,"%x",Ch);
strcat(szInputHexKey,szHexKeyCh);
}
if(!strcmp(szInputHexKey,szInnerHexKey)){
printf("success!\n");
}else{
printf("wring!\n");
}
}
}
对比半F5的结果
int __cdecl main(int argc,const char**argv,const char**envp)
{
signed int v3;// ebx
char v4;// al
int result;// eax
int v6;// [esp+0h] [ebp-70h]
int v7;// [esp+0h] [ebp-70h]
char loc_szHexKeyCh[2];// [esp+12h] [ebp-5Eh]
char loc_szInputKey[20];// [esp+14h] [ebp-5Ch]
char loc_szInputHexKey[36];// [esp+28h] [ebp-48h]
char loc_szInnerHexKey[36];// [esp+4Ch] [ebp-24h]
strcpy(loc_szInnerHexKey,"437261636b4d654a757374466f7246756e");
while(1)
{
memset(loc_szInputHexKey,0,0x20u);
*(_WORD*)&loc_szInputHexKey[32]=0;
loc_szInputHexKey[34]=0;
printf(aPleaseInputYou,v6);
scanf(aS,loc_szInputKey);
if(strlen(loc_szInputKey)>0x11)
break;
v3=0;
do
{
v4=loc_szInputKey[v3];
if(!v4)
break;
sprintf(loc_szHexKeyCh,asc_408044,v4);
strcat(loc_szInputHexKey,loc_szHexKeyCh);
++v3;
}
while(v3<17);
if(!strcmp(loc_szInputHexKey,loc_szInnerHexKey))
printf(aSuccess,v7);
else
printf(aWrong,v7);
}
printf(aWrong,v7);
result=Hi__iob_stru_408090._cnt---1;
if(Hi__iob_stru_408090._cnt<0)
return _filbuf(&Hi__iob_stru_408090);
++Hi__iob_stru_408090._ptr;
return result;
}
其中
result=Hi__iob_stru_408090._cnt---1;
if(Hi__iob_stru_408090._cnt<0)
return _filbuf(&Hi__iob_stru_408090);
++Hi__iob_stru_408090._ptr;
业务逻辑经测试时getchar()的展开。
Hi__iob_stru_408090 结构的引用再运行时环境初始化向量函数 ___initstdio 中引用
.data:0040800C dd offset ___initstdio
.data:00408010 dd offset ___initmbctable
由VC 6.0 d crt源码可知其为
FILE _iob[_IOB_ENTRIES];
开始第一个元素为stdin的定义
/*
* FILE descriptors; preset for stdin/out/err (note that the __tmpnum field
* is not initialized)
*/
FILE _iob[_IOB_ENTRIES] = {
/* _ptr, _cnt, _base, _flag, _file, _charbuf, _bufsiz */
/* stdin (_iob[0]) */
{ _bufin, 0, _bufin, _IOREAD | _IOYOURBUF, 0, 0, _INTERNAL_BUFSIZ },
/* stdout (_iob[1]) */
{ NULL, 0, NULL, _IOWRT, 1, 0, 0 },
/* stderr (_iob[3]) */
{ NULL, 0, NULL, _IOWRT, 2, 0, 0 },
};
结合getchar的定义,可以相互印证上述逻辑代码为getchar()
#define getc(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream))
#define putc(_c,_stream) (--(_stream)->_cnt >= 0 ? 0xff & (*(_stream)->_ptr++ = (char)(_c)) : _flsbuf((_c),(_stream)))
#define getchar() getc(stdin)
#define putchar(_c) putc((_c),stdout)
全程未曾运行样例程序的情况下做的分析。若运行,测试上述代码估计也能猜测到是getc一类函数。
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)