首页
社区
课程
招聘
[原创] 第三题:街机少年解题步骤--连蒙带猜爆破
发表于: 2019-12-6 13:56 4527

[原创] 第三题:街机少年解题步骤--连蒙带猜爆破

2019-12-6 13:56
4527

引用

工具:ida pro7.0
使用ida打开文件,可以看到函数表。其中有个名字较start的,本来想顺着这个start的调用一直跟下去找的处理逻辑,但跟了几层之后觉得有点烦,就决定先找字符串。

往上拖到开头,本来是想看下什么版本的分析之类的,结果第一个函数里就看到命令行输出的字符串,基本可以确认就是程序逻辑,于是分析调用和处理流程。

用于控制台输入输出的函数从上下文可以直接分析出来,比如这个sub_40471D显然就是输出,所以不用跟进去。
得到大致流程:
逐个字符的获取输入的用户名,序列号,以及长度,分别存入全局变量,从这里可以看出数据长度限制。

然后输入的序列号经过一个处理函数,生成真正的密码和长度。经过分析,这个处理函数将输入的四个58-122之间的字节为一组,通过位运算映射为三个字节。。。这就是一个base64算法的变形,58-122刚好也就是64个,'z'相当于标准base64的'=',这可能是我唯一熟悉的加密算法来。至少这一步可以确定是可逆的,有点感动。

接下来通过XREF找到调用getinput的地方,发现接下来过程很直接,就是将第一步得到的用户名和密码通过一个函数处理判断是否正确,因此关键的验证逻辑就是checkpass这个函数了。


解题的过程中顺便看了看题主的发帖记录,找到这样一篇,也是类似的题目。
题目设计非常精巧,反正我是看不懂。并且总是强调多解就女装什么的。。。不知道是自信还是其实想女装(小声)
虽然题目肯定不一样,但是还是能得到一些启发。例如里面的描述方法对理解本题有些帮助,可以把base64得到的密码当成指令来看待。
chekpass代码特别长,毕竟是核心算法,经过分析密码和用户名的调用(这里是只读的)以及如何让函数返回正确,可以将验证逻辑大致可以解释为以下几步:
  1. 将用户名的第一位经过一系列运算得到一个初始值。
  2. 将用户名其余部分调用一个函数经过一系列运算,修改了一个长度15的数组(实际是char[256]但是只有前十五个字符在使用),暂且把这个表当成hash(就是取个名),这个表在后续步骤中使用,而用户名再也没有用过。
  3. 进入循环,每次取出密码中的一项经过一系列复杂操作,分别取高位和低位经过几个循环迭代,得到结果,过程中用到并改变的1中生成的初始值(当成译码看待),最后用这个密码字符得到的指令,修改了hash表中的指定一项(这里里我称为主动修改)。          (这一步里有一个校验指令的过程,可能导致循环退出,具体条件太复杂我也看不懂。只能知道不能走到这个条件)因为代码译码的过程用的变量太多,难以一一分析,所以我暂时没有先研究具体过程,只看这整个步骤对结果的影响。
  4. 取出了密码中的该项和下一项,经过运算,修改了3中译码操作需要用到的一些值,再加上3中也修改了部分变量,也就是改变了下一次译码的规则,这就是说我们不能从数据到指令建立一个一一映射的关系,因此很难倒推回去。
  5. 从hash表中取出所有数据,经过一系列操作作为数组下标,几次迭代,最后从一个大的表中取出一个数据,根据这个数据来进入一个判断,也就是步骤6。
  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代码特别长,毕竟是核心算法,经过分析密码和用户名的调用(这里是只读的)以及如何让函数返回正确,可以将验证逻辑大致可以解释为以下几步:
  1. 将用户名的第一位经过一系列运算得到一个初始值。
  2. 将用户名其余部分调用一个函数经过一系列运算,修改了一个长度15的数组(实际是char[256]但是只有前十五个字符在使用),暂且把这个表当成hash(就是取个名),这个表在后续步骤中使用,而用户名再也没有用过。
  3. 进入循环,每次取出密码中的一项经过一系列复杂操作,分别取高位和低位经过几个循环迭代,得到结果,过程中用到并改变的1中生成的初始值(当成译码看待),最后用这个密码字符得到的指令,修改了hash表中的指定一项(这里里我称为主动修改)。          (这一步里有一个校验指令的过程,可能导致循环退出,具体条件太复杂我也看不懂。只能知道不能走到这个条件)因为代码译码的过程用的变量太多,难以一一分析,所以我暂时没有先研究具体过程,只看这整个步骤对结果的影响。
  4. 取出了密码中的该项和下一项,经过运算,修改了3中译码操作需要用到的一些值,再加上3中也修改了部分变量,也就是改变了下一次译码的规则,这就是说我们不能从数据到指令建立一个一一映射的关系,因此很难倒推回去。
  5. 从hash表中取出所有数据,经过一系列操作作为数组下标,几次迭代,最后从一个大的表中取出一个数据,根据这个数据来进入一个判断,也就是步骤6。
  6. case1:从另一个表中取出数据修改hash,并且是把hash中的每一项都改变,因此既有可能产生0,也有可能把之前已经消为0的值变为非0,造成破坏性后果,具体会发生什么很难分析;case2,有一个指针指向hash中的数据,每次进入这个分支会改变hash中的一个数据,并且重要的是,根据判断条件,只会改变>=1的一个数据(写的时候才突然意识到这一点),而且这里指针指向采用+4%15的方法,可以遍历整个hash表。这一步我称之为被动修改。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2019-12-6 19:28 被mb_ibocelll编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
最新回复 (6)
雪    币: 47147
活跃值: (20445)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
建议写详细些
2019-12-6 14:13
0
雪    币: 3239
活跃值: (435)
能力值: ( LV6,RANK:151 )
在线值:
发帖
回帖
粉丝
3
我尽力了,再多已经写不出来了,最多贴点图
2019-12-6 18:56
0
雪    币: 11705
活跃值: (975)
能力值: ( LV12,RANK:779 )
在线值:
发帖
回帖
粉丝
4
大众队黑马车手,太强了
2019-12-8 12:26
0
雪    币: 3239
活跃值: (435)
能力值: ( LV6,RANK:151 )
在线值:
发帖
回帖
粉丝
5
大佬别说了,我害怕[瑟瑟发抖]
2019-12-8 12:58
0
雪    币: 3239
活跃值: (435)
能力值: ( LV6,RANK:151 )
在线值:
发帖
回帖
粉丝
6
我错了,这里不该用strcpy的,要是中间有个0就完了
2019-12-8 12:59
0
雪    币: 200
活跃值: (87)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
牛皮哦
2019-12-9 11:20
0
游客
登录 | 注册 方可回帖
返回
//