引用
工具:ida pro7.0
使用ida打开文件,可以看到函数表。其中有个名字较start的,本来想顺着这个start的调用一直跟下去找的处理逻辑,但跟了几层之后觉得有点烦,就决定先找字符串。
往上拖到开头,本来是想看下什么版本的分析之类的,结果第一个函数里就看到命令行输出的字符串,基本可以确认就是程序逻辑,于是分析调用和处理流程。
用于控制台输入输出的函数从上下文可以直接分析出来,比如这个sub_40471D显然就是输出,所以不用跟进去。
得到大致流程:
逐个字符的获取输入的用户名,序列号,以及长度,分别存入全局变量,从这里可以看出数据长度限制。
然后输入的序列号经过一个处理函数,生成真正的密码和长度。经过分析,这个处理函数将输入的四个58-122之间的字节为一组,通过位运算映射为三个字节。。。这就是一个base64算法的变形,58-122刚好也就是64个,'z'相当于标准base64的'=',这可能是我唯一熟悉的加密算法来。至少这一步可以确定是可逆的,有点感动。
接下来通过XREF找到调用getinput的地方,发现接下来过程很直接,就是将第一步得到的用户名和密码通过一个函数处理判断是否正确,因此关键的验证逻辑就是checkpass这个函数了。
题目设计非常精巧,反正我是看不懂。并且总是强调多解就女装什么的。。。不知道是自信还是其实想女装(小声)
虽然题目肯定不一样,但是还是能得到一些启发。例如里面的描述方法对理解本题有些帮助,可以把base64得到的密码当成指令来看待。
chekpass代码特别长,毕竟是核心算法,经过分析密码和用户名的调用(这里是只读的)以及如何让函数返回正确,可以将验证逻辑大致可以解释为以下几步:
- 将用户名的第一位经过一系列运算得到一个初始值。
- 将用户名其余部分调用一个函数经过一系列运算,修改了一个长度15的数组(实际是char[256]但是只有前十五个字符在使用),暂且把这个表当成hash(就是取个名),这个表在后续步骤中使用,而用户名再也没有用过。
- 进入循环,每次取出密码中的一项经过一系列复杂操作,分别取高位和低位经过几个循环迭代,得到结果,过程中用到并改变的1中生成的初始值(当成译码看待),最后用这个密码字符得到的指令,修改了hash表中的指定一项(这里里我称为主动修改)。 (这一步里有一个校验指令的过程,可能导致循环退出,具体条件太复杂我也看不懂。只能知道不能走到这个条件)因为代码译码的过程用的变量太多,难以一一分析,所以我暂时没有先研究具体过程,只看这整个步骤对结果的影响。
- 取出了密码中的该项和下一项,经过运算,修改了3中译码操作需要用到的一些值,再加上3中也修改了部分变量,也就是改变了下一次译码的规则,这就是说我们不能从数据到指令建立一个一一映射的关系,因此很难倒推回去。
- 从hash表中取出所有数据,经过一系列操作作为数组下标,几次迭代,最后从一个大的表中取出一个数据,根据这个数据来进入一个判断,也就是步骤6。
- case1:从另一个表中取出数据修改hash,并且是把hash中的每一项都改变,因此既有可能产生0,也有可能把之前已经消为0的值变为非0,造成破坏性后果,具体会发生什么很难分析;case2,有一个指针指向hash中的数据,每次进入这个分支会改变hash中的一个数据,并且重要的是,根据判断条件,只会改变>=1的一个数据(写的时候才突然意识到这一点),而且这里指针指向采用+4%15的方法,可以遍历整个hash表。这一步我称之为被动修改。
可是我确实就不会反调试,也不知道断点要下在哪,也不想试,所以只能先假设没有什么变形,试试运气(实际上我觉得这个算法这么复杂,是假的可能性不大,而且各个数据表从ida的xref里也没找到别的读写,但是也有可能在初始化时产生了新的函数修改了部分表)。
KCTF2019
Please input your username: ( A to Z, a to z, 0 to 9 )
f3a25f8b29bb9cbc
Please input your KEY: ( : to z )
JXg@vwrpfoLbRcxvdYrvv[kyRSso
hashis:1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 14, 15,
hashis:5, 1, 6, 3, 3, 7, 7, 10, 9, 10, 7, 6, 6, 10, 11,
ind:0, pass:65
change:id14+=-5
hashis:5, 1, 6, 3, 3, 7, 7, 10, 9, 10, 7, 6, 6, 10, 6,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 10, 7, 6, 6, 10, 6,
ind:1, pass:-19
change:id14+=-6
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 10, 7, 6, 6, 10, 0,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 10, 0,
ind:2, pass:-122
change:id13+=-3
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 7, 0,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 4, 0,
ind:3, pass:-13
change:id12+=-1
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 4, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 4, 0,
ind:4, pass:-40
change:id13+=-2
hashis:5, 1, 0, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 2, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 7, 6, 5, 2, 0,
ind:5, pass:-10
change:id13+=-1
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 7, 6, 5, 1, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 3, 6, 5, 1, 0,
ind:6, pass:-77
change:id12+=-4
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 3, 6, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 10, 9, 7, 3, 6, 1, 1, 0,
ind:7, pass:82
change:id11+=-2
hashis:5, 1, 0, 1, 3, 1, 4, 10, 9, 7, 3, 4, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 3, 4, 1, 1, 0,
ind:8, pass:104
change:id10+=-3
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 0, 4, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 0, 1, 1, 1, 0,
ind:9, pass:98
change:id9+=-5
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 2, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 3, 1, 4, 9, 9, 2, 0, 1, 1, 1, 0,
ind:10, pass:-98
change:id6+=-2
hashis:3, 1, 0, 1, 3, 1, 2, 9, 9, 2, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 9, 9, 2, 0, 1, 1, 1, 0,
ind:11, pass:-4
change:id9+=-1
hashis:3, 1, 0, 1, 0, 1, 2, 9, 9, 1, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 9, 6, 1, 0, 1, 1, 1, 0,
ind:12, pass:-87
change:id7+=-3
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 1, 0,
ind:13, pass:-8
change:id13+=-1
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 0, 0,
ind:14, pass:-4
change:id11+=-1
hashis:3, 0, 0, 1, 0, 1, 2, 6, 6, 1, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 0, 2, 6, 6, 1, 0, 0, 0, 0, 0,
ind:15, pass:-14
change:id9+=-1
hashis:3, 0, 0, 1, 0, 0, 2, 6, 6, 0, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0,
ind:16, pass:17
change:id8+=-2
hashis:3, 0, 0, 1, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
ind:17, pass:-1
change:id0+=-1
hashis:2, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
case2:
hashis:2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0,
ind:18, pass:97
change:id8+=-3
hashis:2, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0,
case2:
hashis:0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0,
ind:19, pass:-103
change:id7+=-2
hashis:0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
case2:
hashis:0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
ind:20, pass:-11
change:id7+=-1
hashis:0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
You Win! You are very clever!
请按任意键继续. . .
int main()
{
char tempcachetable[256]={0},temphashname[256]={0};
strcpy(tempcachetable,cachetable);//保存初始表格
strcpy(temphashname,hashname);
char *constname="KCTF";
len_name=4;
strcpy(uname,constname);
bool run=true;
int k=0;
while(run){
for(int i=0;i<256;i++){
strcpy(cachetable,tempcachetable);
strcpy(hashname,temphashname);
pass[k]=(char)i;
passlen=k+1;
if(checkpass((unsigned __int8 *)uname, len_name))
{run=false;cout<<"success!!!"<<endl;break;}//最后一次是主动修改完成,不需要进入case2,已经直接得到了答案
if(iscase2){
cout<<endl<<k<<"--------------"<<i<<endl<<endl;
iscase2=false;
break;
}
if(i==255){cout<<"failed"<<endl;return 0;}
}
k++;
if(k>=96){
cout<<"failed"<<endl;
break;
}
int jj;
cout<<"pass:";
for ( jj = 0; jj <passlen; ++jj )
{
cout<<(int)pass[jj]<<", ";
}
cout<<"len is:"<<passlen<<endl;
}
char result[256]={0};//base64加密结果
ab64e(pass,result,passlen);
cout<<result<<endl;
cout<<endl;
/*
if ( getinput() )
{
if ( checkpass((unsigned __int8 *)uname, len_name) )
cout<<"You Win! You are very clever!"<<endl;
else
cout<<"Game Over"<<endl;
system("pause");
}
else
{
cout<<"Game Over"<<endl;
system("pause");
}
*/
return 0;
完整程序见附件。
程序跑起来很快,把多余的输出关了基本就是秒解。
接下来就是从密码解出序列号,需要写一个base64编码的规则,本来以为这是最简单的,结果因为代码太渣,脑子太卡,甚至还写出了栈溢出。。。。主要就是各种左移右移掩码,原程序汇编代码里有一个sar算术右移,被ida翻译成signed类型,其实最高位都是0没什么影响,所以在编码的时候要全部用逻辑左/右移,也就是unsigned,另外比较麻烦的就是长度不能被三整除的情况,这样最后需要特殊处理,补上’z'。
然后把生成的序列号输入原程序,竟然失败了,当时就心里一凉。幸好把序列号输入自己的程序也失败了,虽然我的程序有问题,但至少还有机会。
经过检查,发现是从提供的用户名改为“KCTF”时忘了改长度,然后就得到正确结果。
这时候已经凌晨一点多了。我记得我本来都掏出手机想打游戏的,游戏加载的时候看了看代码,结果就没能停下来,最后发现游戏都已经被杀后台了。
提交的时候发现还没人提交,心情有点激动,差点睡不着。转念一想这题难不难不知道,但是我能做出了确实是凑巧。
其实最主要的原因是花的时间多吧,一下午加一晚上,十二个小时不知道有没有,真正的大佬估计是在忙别的没这么多时间,毕竟是工作日。
本人没什么经验,第一题就做了两小时,一半在MFC打转,第二题在py虚拟机里转了两天还去搞了patch文件然后子进程调试和脱壳之类的,最后终于醒悟过来拿到py代码查出来是rsa后也分解不了。
综上所述,做这道题,靠的就是运气好,蒙对了。不过我觉得这题挺有意思的,虽然看不懂原理但是感觉很精妙。
KCTF2019
Please input your username: ( A to Z, a to z, 0 to 9 )
f3a25f8b29bb9cbc
Please input your KEY: ( : to z )
JXg@vwrpfoLbRcxvdYrvv[kyRSso
hashis:1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 14, 15,
hashis:5, 1, 6, 3, 3, 7, 7, 10, 9, 10, 7, 6, 6, 10, 11,
ind:0, pass:65
change:id14+=-5
hashis:5, 1, 6, 3, 3, 7, 7, 10, 9, 10, 7, 6, 6, 10, 6,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 10, 7, 6, 6, 10, 6,
ind:1, pass:-19
change:id14+=-6
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 10, 7, 6, 6, 10, 0,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 10, 0,
ind:2, pass:-122
change:id13+=-3
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 7, 0,
case2:
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 6, 4, 0,
ind:3, pass:-13
change:id12+=-1
hashis:5, 1, 6, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 4, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 4, 0,
ind:4, pass:-40
change:id13+=-2
hashis:5, 1, 0, 3, 3, 1, 7, 10, 9, 7, 7, 6, 5, 2, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 7, 6, 5, 2, 0,
ind:5, pass:-10
change:id13+=-1
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 7, 6, 5, 1, 0,
case2:
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 3, 6, 5, 1, 0,
ind:6, pass:-77
change:id12+=-4
hashis:5, 1, 0, 3, 3, 1, 4, 10, 9, 7, 3, 6, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 10, 9, 7, 3, 6, 1, 1, 0,
ind:7, pass:82
change:id11+=-2
hashis:5, 1, 0, 1, 3, 1, 4, 10, 9, 7, 3, 4, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 3, 4, 1, 1, 0,
ind:8, pass:104
change:id10+=-3
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 0, 4, 1, 1, 0,
case2:
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 7, 0, 1, 1, 1, 0,
ind:9, pass:98
change:id9+=-5
hashis:5, 1, 0, 1, 3, 1, 4, 9, 9, 2, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 3, 1, 4, 9, 9, 2, 0, 1, 1, 1, 0,
ind:10, pass:-98
change:id6+=-2
hashis:3, 1, 0, 1, 3, 1, 2, 9, 9, 2, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 9, 9, 2, 0, 1, 1, 1, 0,
ind:11, pass:-4
change:id9+=-1
hashis:3, 1, 0, 1, 0, 1, 2, 9, 9, 1, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 9, 6, 1, 0, 1, 1, 1, 0,
ind:12, pass:-87
change:id7+=-3
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 1, 1, 0,
case2:
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 1, 0,
ind:13, pass:-8
change:id13+=-1
hashis:3, 1, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 1, 2, 6, 6, 1, 0, 1, 0, 0, 0,
ind:14, pass:-4
change:id11+=-1
hashis:3, 0, 0, 1, 0, 1, 2, 6, 6, 1, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 0, 2, 6, 6, 1, 0, 0, 0, 0, 0,
ind:15, pass:-14
change:id9+=-1
hashis:3, 0, 0, 1, 0, 0, 2, 6, 6, 0, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 1, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0,
ind:16, pass:17
change:id8+=-2
hashis:3, 0, 0, 1, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
case2:
hashis:3, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
ind:17, pass:-1
change:id0+=-1
hashis:2, 0, 0, 0, 0, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0,
case2:
hashis:2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0,
ind:18, pass:97
change:id8+=-3
hashis:2, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0,
case2:
hashis:0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0,
ind:19, pass:-103
change:id7+=-2
hashis:0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
case2:
hashis:0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
ind:20, pass:-11
change:id7+=-1
hashis:0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
You Win! You are very clever!
请按任意键继续. . .
int main()
{
char tempcachetable[256]={0},temphashname[256]={0};
strcpy(tempcachetable,cachetable);//保存初始表格
strcpy(temphashname,hashname);
char *constname="KCTF";
len_name=4;
strcpy(uname,constname);
bool run=true;
int k=0;
while(run){
for(int i=0;i<256;i++){
strcpy(cachetable,tempcachetable);
strcpy(hashname,temphashname);
pass[k]=(char)i;
passlen=k+1;
if(checkpass((unsigned __int8 *)uname, len_name))
{run=false;cout<<"success!!!"<<endl;break;}//最后一次是主动修改完成,不需要进入case2,已经直接得到了答案
if(iscase2){
cout<<endl<<k<<"--------------"<<i<<endl<<endl;
iscase2=false;
break;
}
if(i==255){cout<<"failed"<<endl;return 0;}
}
k++;
if(k>=96){
cout<<"failed"<<endl;
break;
}
int jj;
cout<<"pass:";
for ( jj = 0; jj <passlen; ++jj )
{
cout<<(int)pass[jj]<<", ";
}
cout<<"len is:"<<passlen<<endl;
}
char result[256]={0};//base64加密结果
ab64e(pass,result,passlen);
cout<<result<<endl;
cout<<endl;
/*
if ( getinput() )
{
if ( checkpass((unsigned __int8 *)uname, len_name) )
cout<<"You Win! You are very clever!"<<endl;
else
cout<<"Game Over"<<endl;
system("pause");
}
else
{
cout<<"Game Over"<<endl;
system("pause");
}
*/
return 0;
工具:ida pro7.0
使用ida打开文件,可以看到函数表。其中有个名字较start的,本来想顺着这个start的调用一直跟下去找的处理逻辑,但跟了几层之后觉得有点烦,就决定先找字符串。
往上拖到开头,本来是想看下什么版本的分析之类的,结果第一个函数里就看到命令行输出的字符串,基本可以确认就是程序逻辑,于是分析调用和处理流程。
用于控制台输入输出的函数从上下文可以直接分析出来,比如这个sub_40471D显然就是输出,所以不用跟进去。
得到大致流程:
逐个字符的获取输入的用户名,序列号,以及长度,分别存入全局变量,从这里可以看出数据长度限制。
然后输入的序列号经过一个处理函数,生成真正的密码和长度。经过分析,这个处理函数将输入的四个58-122之间的字节为一组,通过位运算映射为三个字节。。。这就是一个base64算法的变形,58-122刚好也就是64个,'z'相当于标准base64的'=',这可能是我唯一熟悉的加密算法来。至少这一步可以确定是可逆的,有点感动。
接下来通过XREF找到调用getinput的地方,发现接下来过程很直接,就是将第一步得到的用户名和密码通过一个函数处理判断是否正确,因此关键的验证逻辑就是checkpass这个函数了。
逐个字符的获取输入的用户名,序列号,以及长度,分别存入全局变量,从这里可以看出数据长度限制。
然后输入的序列号经过一个处理函数,生成真正的密码和长度。经过分析,这个处理函数将输入的四个58-122之间的字节为一组,通过位运算映射为三个字节。。。这就是一个base64算法的变形,58-122刚好也就是64个,'z'相当于标准base64的'=',这可能是我唯一熟悉的加密算法来。至少这一步可以确定是可逆的,有点感动。
接下来通过XREF找到调用getinput的地方,发现接下来过程很直接,就是将第一步得到的用户名和密码通过一个函数处理判断是否正确,因此关键的验证逻辑就是checkpass这个函数了。
题目设计非常精巧,反正我是看不懂。并且总是强调多解就女装什么的。。。不知道是自信还是其实想女装(小声)
虽然题目肯定不一样,但是还是能得到一些启发。例如里面的描述方法对理解本题有些帮助,可以把base64得到的密码当成指令来看待。
chekpass代码特别长,毕竟是核心算法,经过分析密码和用户名的调用(这里是只读的)以及如何让函数返回正确,可以将验证逻辑大致可以解释为以下几步:
- 将用户名的第一位经过一系列运算得到一个初始值。
- 将用户名其余部分调用一个函数经过一系列运算,修改了一个长度15的数组(实际是char[256]但是只有前十五个字符在使用),暂且把这个表当成hash(就是取个名),这个表在后续步骤中使用,而用户名再也没有用过。
- 进入循环,每次取出密码中的一项经过一系列复杂操作,分别取高位和低位经过几个循环迭代,得到结果,过程中用到并改变的1中生成的初始值(当成译码看待),最后用这个密码字符得到的指令,修改了hash表中的指定一项(这里里我称为主动修改)。 (这一步里有一个校验指令的过程,可能导致循环退出,具体条件太复杂我也看不懂。只能知道不能走到这个条件)因为代码译码的过程用的变量太多,难以一一分析,所以我暂时没有先研究具体过程,只看这整个步骤对结果的影响。
- 取出了密码中的该项和下一项,经过运算,修改了3中译码操作需要用到的一些值,再加上3中也修改了部分变量,也就是改变了下一次译码的规则,这就是说我们不能从数据到指令建立一个一一映射的关系,因此很难倒推回去。
- 从hash表中取出所有数据,经过一系列操作作为数组下标,几次迭代,最后从一个大的表中取出一个数据,根据这个数据来进入一个判断,也就是步骤6。
- case1:从另一个表中取出数据修改hash,并且是把hash中的每一项都改变,因此既有可能产生0,也有可能把之前已经消为0的值变为非0,造成破坏性后果,具体会发生什么很难分析;case2,有一个指针指向hash中的数据,每次进入这个分支会改变hash中的一个数据,并且重要的是,根据判断条件,只会改变>=1的一个数据(写的时候才突然意识到这一点),而且这里指针指向采用+4%15的方法,可以遍历整个hash表。这一步我称之为被动修改。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-12-6 19:28
被mb_ibocelll编辑
,原因: