求xingfu12884 解压密码 😀

runas命令 自动输入密码,求批处理脚-中国学网-中国IT综合门户网站
> 信息中心 >
runas命令 自动输入密码,求批处理脚
来源:互联网 发表时间: 10:59:06 责任编辑:鲁晓倩字体:
为了帮助网友解决“runas命令 自动输入密码,求批处理脚”相关的问题,中国学网通过互联网对“runas命令 自动输入密码,求批处理脚”相关的解决方案进行了整理,用户详细问题包括:<,具体解决方案如下:解决方案1: 批处理无法做到,我研究过了~~~ 能说说你是想做什么吗?我前次用到这个命令是我想做一个批处理,实现自动注销,才涉及到这个命令,但是研究了两天都没研究出结果,最后我用另外的方法解决了。。。可以去我的QQ 空间看看,《监视指定进程--发现进程后立即注销/重启/关机》这个批处理就是能涉及到这个命令的,后来用其他方法解决!要用VBS的话,可以再网上搜搜啊...不过我觉得一点都不好。没什么意思..因为是靠虚拟按键操作。。运行的时候要打开这个窗口才能自动输入密码...不行! 不适用!下面是我在网上搜的:方法一:使用VBS的SendKeys来输入密码echo set pws=WScript.CreateObject(&WScript.Shell&)&%temp%\pws.vbsecho pws.SendKeys &1{ENTER}&&&%temp%\pws.vbswscript %temp%\pws.vbs&runas /u:test1 cmd.exe方法二:使用/savecred参数独立用户执行程序时第一次需要建立凭据,其间输入密码是不会回显的,你看不到,输了后回车即可。以后在运行就不需要输入密码了。runas /u:test1 cmd.exe 输入密码并回车runas /savecred /u:test1 explorer 不用输密码了 方法三:用PsTools工具中的PsExec来替代 Runas方法四:使用/sa参数runas /u:admin /sa cmd这是用VBS的:http://kingoa.net/script/vbs/9.html
3个回答1个回答1个回答3个回答1个回答2个回答1个回答3个回答3个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答1个回答
相关文章:
最新添加资讯
24小时热门资讯
Copyright &#169; 2004- All Rights Reserved. 中国学网 版权所有
京ICP备号-1 京公网安备02号5 秒后返回
微信扫一扫精选音乐每日推送!在Mac下重新设置mysql 的密码 &出现的一些问题:# mysql -uroot -pEnter password:ERROR ): Access denied for user 'root'@'localhost' (using password: NO)使用网上介绍的方法修改root用户的密码:# mysqladmin -uroot -p password 'newpassword'Enter password:mysqladmin: connect to server at 'localhost' failederror: 'Access denied for user 'root'@'localhost' (using password: YES)'现在终于被我找到了解决方法,如下(请先测试方法三,谢谢!):方法一:# /etc/init.d/mysql stop# mysqld_safe --user=mysql --skip-grant-tables --skip-networking &# mysql -u root mysqlmysql& UPDATE user SET Password=PASSWORD('newpassword') where USER='root';mysql& FLUSH PRIVILEGES;mysql& quit# /etc/init.d/mysql restart# mysql -uroot -pEnter password: &输入新设的密码newpassword&mysql&&一、MySQL修改密码方法总结首先要说明一点的是:一般情况下,修改MySQL密码是需要有mysql里的root权限的,这样一般用户是无法更改密码的,除非请求管理员帮助修改。     方法一     使用phpMyAdmin  (图形化管理MySql数据库的工具),这是最简单的,直接用SQL语句修改mysql数据库库的user表,不过别忘了使用PASSWORD函数,插入用户用Insert命令,修改用户用Update命令,删除用Delete命令。在本节后面有数据表user字段的详细介绍。     方法二     使用mysqladmin。输入    mysqladmin -u root -p oldpassword newpasswd  执行这个命令后,需要输入root的原密码,这样root的密码将改为newpasswd。同样,把命令里的root改为你的用户名,你就可以改你自己的密码了。  当然如果你的mysqladmin连接不上mysql  server,或者你没有办法执行mysqladmin,那么这种方法就是无效的,而且mysqladmin无法把密码清空。     下面的方法都在mysql提示符下使用,且必须有mysql的root权限:     方法三     mysql& INSERT INTO mysql.user (Host,User,Password) VALUES  ('%','system', PASSWORD('manager'));  mysql& FLUSH PRIVILEGES     确切地说这是在增加一个用户,用户名为system,密码为manager。注意要使用PASSWORD函数,然后还要使用FLUSH  PRIVILEGES来执行确认。     方法四     和方法三一样,只是使用了REPLACE语句  mysql& REPLACE INTO mysql.user (Host,User,Password)VALUES('%','system',PASSWORD('manager'));  mysql& FLUSH PRIVILEGES    方法五     使用SET PASSWORD语句     mysql& SET PASSWORD FOR system@&%& = PASSWORD('manager');     你也必须使用PASSWORD()函数,但是不需要使用FLUSH PRIVILEGES来执行确认。   方法六     使用GRANT ... IDENTIFIED BY语句,来进行授权。     mysql& GRANT USAGE ON *.* TO system@&%& IDENTIFIED BY 'manager';     这里PASSWORD()函数是不必要的,也不需要使用FLUSH PRIVILEGES来执行确认。     注:PASSWORD()函数作用是为口令字加密,在程序中MySql自动解释。    二、MySql中访问限制的设置方法  我们采用两种方法来设置用户。  进入到Mysql执行目录下(通常是c:/mysql/bin)。输入mysqld-shareware.exe,输入mysql  --user=root mysql ,不然不能添加新用户。进入到mysql&提示符下进行操作。     假设我们要建立一个超级用户,用户名为system,用户口令为manager。    方法一    用Grant 命令授权,输入的代码如下:  mysql&GRANT ALL PRIVILEGES ON *.* TO system@localhost IDENTIFIED BY  'manager' WITH GRANT OPTION;     应显示:Query OK, 0 rows affected (0.38 sec)  方法二     对用户的每一项权限进行设置:     mysql&INSERT INTO user  VALUES('localhost','system',PASSWORD('manager'),  'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');  对于3.22.34版本的MySQL,这里共14个&Y&,其相应的权限如下(按字段顺序排列):     权限 表列名称 相应解释 使用范围  select Select_priv 只有在真正从一个表中检索时才需要select权限 表  insert Insert_priv 允许您把新行插入到一个存在的表中 表  update Update_priv 允许你用新&#20540;更新现存表中行的列 表  delete Delete_priv 允许你删除满足条件的行 表  create Create_priv 允许你创建新的数据库和表 数据库、表或索引  drop Drop_priv 抛弃(删除)现存的数据库和表 数据库或表&&&&&&& reload Reload_priv 允许您告诉服务器再读入授权表 服务器管理  shutdown Shutdown_priv 可能被滥用(通过终止服务器拒绝为其他用户服务) 服务器管理  process Process_priv 允许您察看当前执行的查询的普通文本,包括设定或改变口令查询 服务器管理  file File_priv 权限可以被滥用在服务器上读取任何可读的文件到数据库表 服务器上的文件存取  grant Grant_priv 允许你把你自己拥有的那些权限授给其他的用户 数据库或表  references References_priv 允许你打开和关闭记录文件 数据库或表  index Index_priv 允许你创建或抛弃(删除)索引 表&&&&&&& alter Alter_priv 允许您改变表&#26684;,可以用于通过重新命名表来推翻权限系统 表    如果创建用户时只有select、insert、update和delete权限,则允许用户只能在一个数据库现有的表上实施操作.  下面就可以创建我们要用到的数据库了,我们直接输入. 例如:我们要创建数据库名为XinXiKu,可用如下代码:    mysql&create database XinXiKu;     应显示:Query OK, 1 row affected (0.00 sec)2015移动安全挑战赛(阿里&看雪主办)全程回顾
本次比赛的第一个题目是一个APK文件,安装后,需要用户输入特定的密码,输入正确会显示成功。该题目的APK文件没有太多的保护,可以直接使用各种分析工具(如jeb等)反编译得到Java代码。
获得正确注册码的代码逻辑为: 1. 从logo.png这张图片的偏移89473处,读取一个映射表,768字节编码成UTF-8,即256个中文表 2. 从偏移91265处读取18个字节编码的UTF-8(即6个中文字符)为最终比较的密码。然后通过输入的字符的转换,转换规则就是ASCII字符编码,去比较是否和最终密码相等。
0x2 巧妙的解法
我们在这里提供一种非常愉快的解法,不需要复杂的工具和分析,大家可以参见视频
打开app后,我们使用adb logcat并加上这个app独有的 lil 标签过滤日志输出,发现app输出日志中有table,pw以及enPassword。随意输入字符串如,发现enPassword中有对应的中文输出,根据输出反馈,可以知道有如下对应关系
1 - 么2 - 广3 - 亡4 - 门5 - 义6 - 之7 - 尸8 - 弓9 - 己
通过观察Logcat输出可知,最终目标pw应为义弓么丸广之,根据上述table中的对应关系,我们可以得到最终密码为:
本次比赛的第二个题目仍然是一个独立的APK文件,安装后,需要用户输入特定的密码,输入正确会显示成功。第二题APK在Java层代码中并没有关键逻辑,将用户输入直接传给native so层中securityCheck这个native method(securityCheck方法在libcrackme.so中),由native code来决定返回正确与否。
用IDA工具打开libcrackme.so,首先看下程序的大致流程,可以看到在securityCheck这个方法调用前,在init_array段和JNI_Onload函数里程序都做了些处理,而在securityCheck方法的最后有一个判断,将用户输入和wojiushidaan做比较。尝试直接输入wojiushidaan,发现密码错误,因此可以猜测前面一大段逻辑的作用就是会把这个最终的字符串改掉。此时的思路是只需知道最终判断时候这个wojiushidaan地址上的变换后的值就行了。尝试使用IDA调试发现一旦attach上去,整个程序就退出,想必一定是在之前的代码中有反调试的代码。
0x2 巧妙的解法
同上一题一样,我们提供一种非常巧妙的解法:
注意到在最终比较之前,程序使用了android_log_print函数,当我们直接运行程序时,发现这里固定输出了
I/yaotong ( XXX): SecurityCheck Started...
这时候我们想,是否可以直接patch这个libcrackme.so,修改打印的内容,直接利用这个函数帮我们输出此时真正需要比较的值。
我们选择patch的方法是直接把这个log函数往下移,因为在0x12A4地址处正好有我们需要的打印的数据地址赋值给了R2寄存器(本来是为了给后面做比较用的),因此将代码段从0xC的地方都用NOP改写,在0x12AC的地方调用log函数,同时为了不影响R1的值,把0x12A0处的R1改成R3。
下面是对比patch前和patch后的图:
参考视频给出了完整的解决过程:
通过观察Logcat输出可知,最终密码为:
aiyou,bucuoo
在介绍本次比赛第三道题目之前,首先要介绍一个我们GoSSIP小组开发的基于Dalvik VM的插桩分析框架InDroid,其设计思想是直接修改AOSP上的Dalvik VM解释器,在解释器解释执行Dalvik字节码时,插入监控的代码,这样就可以获取到所有程序运行于Dalvik上的动态信息,如执行的指令、调用的方法信息、参数返回值、各种Java对象的数据等等。InDroid只需要修改AOSP的dalvik vm部分代码,编译之后,可直接将编译生成的新libdvm.so刷入任何AOSP支持的真机设备上(目前我们主要使用Nexus系列机型特别是Nexus4和Galaxy Nexus)。在本次比赛的第三题和第四题分析过程中,我们使用该工具进行分析,大大提高了分析效率。
回到题目上,将第三题的APK进行反编译后发现代码使用了加壳保护,对付这类加壳的APK,最方便的方法就是使用InDroid来进行动态监控,因为静态的DEX一定会在执行时在Dalvik上时解密执行,这样我们可以直接在InDroid框架里对解释执行过程中释放出来的指令进行监控。在我们自己使用的工具里,我们开发了一个动态读取整个dex信息的接口,执行时去读DexFile这个结构,然后对其进行解析(解析时直接复用了Android自带的dexdump的代码)。这样,我们的插桩工具在运行程序后,能够直接得到程序的dex信息,同未经保护时使用dexdump后得到的结果基本一致。虽然我们得到的信息是dalvik字节码,没有直接反编译成代码那么友好,但由于程序不大,关键逻辑不多,因此对我们的分析效率影响并不大。
在得到脱壳之后的dexdump结果后,我们可以对代码进行静态分析。我们发现用户的输入会传递给继承自Class timertask的Class b,被Class b的run方法处理。在run方法中,如果sendEmptyMessage方法被调用时的参数为0,就会导致Class c的handleMessage这个方法中得到的message的what值为0,进而导致103除0跳入异常处理中,触发成功的提示。
继续分析这个run方法的逻辑,可以知道用户的输入会被传递到Class e的a方法中,做个类似摩尔斯译码的过程(其译码与标准的摩尔斯电码不太一样),然后经过下面一系列大量的混淆用的无用处理和不可能相等的比较后,将译码后得到的字符串送入到关键的判断中去。这个判断成功的条件比较复杂:对于译码后得到的字符串的前两个字节,要求使用hashcode方法的结果等于3618,并且这两个字节相加等于168,才会进入后面的比较。我们穷搜索一下符合这类输入的字符串:
for ( size_t i = 33; i & 127; ++i )
for ( size_t j = 33; j & 127; ++j )
String x =String.valueOf((char)j)+String.valueOf((char)i);
if (x.hashCode()==3618 && (i+j) == 168)
System.out.println(x);
System.out.println(j+i);
也就是说只有s5满足hashcode为3618,而相加等于168这个条件。
确定前两个字符后,后面还有四个字符需要同Class e和Class a的Annotation值比较。因为我们做脱壳的时候直接使用了dexdump的代码,而dexdump即使到最新版里也无法很好地处理Annotations:
// TODO: Annotations.
不过没关系,我们还有动态分析工具这一利器,因为最终目的是得到getAnnotation方法的返回值,依然可以用InDroid在Dalvik执行到getAnnotation方法时监控返回值,就能得到Annotation的具体值。使用InDroid获取具体信息的视频如下:
最后可知,符合程序需求的字符串是
使用程序内部的对应表,对其进行逆变换,能够让程序输入成功提示的输入应该是:
& _____ ____. . ..___ .__.
本次移动安全挑战赛的第四题和第三题一样,是一个包含了加壳dex的APK文件,我们使用同解决上一题一样的方法,用InDroid得到原始dex文件的dexdump结果:
使用InDroid进行脱壳的演示视频:
Dex整体处理过程和上一题也类似,使用handleMessage处理最后的判断输入成功与否,只有sendEmptyMessage(0)后,触发除以0的异常才能成功。不过这一题将用户输入转成byte后,传给一个native的方法:ali$a的M$j方法,另外参数还包括一个常数48和Handler。看样子逆向native库势在必行了。这一题的lib文件夹下文件和上一题是一样的,有三个文件,其中libmobisecy.so其实是个zip文件,解压后是个classes.dex,直接反汇编后,类和方法的名字都在,只是里面的代码都是
throw new RuntimeException();
而libmobisecz.so直接就是一堆binary数据,猜测应该是运行时会被解密,通过某种方式映射到为真正的代码执行。因此我们的目标就是libmobisec.so这个ELF文件。
直接用IDA打开libmobisec.so,发现IDA会崩溃。用readelf发现正常的节区头数据都被破坏了,因此应该这个so本身也被加过壳了,很多数据只有在动态运行时才会解开,所以直接使用动态的方法,先运行这个程序后,直接在内存中把这个so dump出来。
首先需要在输入框中随便输入些数据后,点击确定,保证用户输入数据执行到native方法里后再做dump。我们使用的方法是查看maps后,使用dd命令把整个so都dump出来。
输入命令:
root@maguro:/ # ps | grep crackme.a4
76 ffffffff 400dc408 S crackme.a4
root@maguro:/ # cat /proc/1935/maps
5e0f000 r-xp :04 741132
/data/app-lib/crackme.a4-1/libmobisec.so
5ee466000 r-xp :00 0
5ee467000 rwxp :00 0
5ee479000 rw-p :00 0
5ee490000 r-xp :04 741132
/data/app-lib/crackme.a4-1/libmobisec.so
5ee491000 rwxp 001a 741132
/data/app-lib/crackme.a4-1/libmobisec.so
5ee492000 rw-p 001a 741132
/data/app-lib/crackme.a4-1/libmobisec.so
5ee493000 rwxp 001aa000 103:04 741132
/data/app-lib/crackme.a4-1/libmobisec.so
5ee4c1000 rw-p 001ab000 103:04 741132
/data/app-lib/crackme.a4-1/libmobisec.so
使用dd命令将libmobisec.so的内存dump出来
root@maguro:/ # dd if=/proc/1935/mem of=/sdcard/alimsc4 skip= ibs=1 count=3993600
dd命令使用的数字都是十进制的,skip就是libmobisec.so的起始地址,count是总长度。 为了让IDA还能够识别libmobisec里的libc函数,我们还需要把libc也载入到IDA中,libc就直接从system/lib里拖出来就行了。
adb pull /system/lib/libc.so ./
用IDA先打开libc,调整好是在内存中的偏移即rebase program,再在load additional binary里载入dd出来的libmobisec.so,通过maps里的偏移后载入。接下来的任务就是在其中找到M\$j这个函数的地址。
一开始尝试直接在dd出来的ELF文件中找这个M\$j这个函数名,类似的名字会被处理成
Java_ali_00024a_M_00024j
类似下图:
不过我没找到这个M\$j这个名字,逆过JNI库的都知道,如果符号表里找不到这个函数名,说明在JNI_Onload的时候,使用RegisterNatives函数重新将一个JNI函数映射为Native函数了。
正当一筹莫展的时候,我再次想起了InDroid系统。在Dalvik中,每个方法都是一个Method的结构体,其中当这个方法是native的时候,Method的insns这个指针会指向native方法的起始地址。因此我们修改了下InDroid,让Dalvik在执行M\$j这个方法前,去打印了M\$j方法的insns指针。这时我们得到了一个指向另一片内存区域的值,既不在libdvm中,也不在libmobisec中,并且这片内存页被映射成了rwx,由此推断里面也极有可能是代码,我们继而又dd出了这块内存,用IDA打开,使用ARM平台反汇编,发现该处就一条指令,是LOAD PC到另一个地址,而这个地址恰好在libmobisec中。于是我们直接到IDA中跳到这个地址,发现正好是个压栈指令,印证了我们的想法,此处就是M$j函数,于是在在IDA里该地址指令处,右击选择create function,让IDA识别这一段汇编指令为函数指令后,就可以通过F5查看看反编译的C代码了。
这个函数本身做了一些控制流混淆,同时还有很多字符串加解密的功能函数,一些简单的如异或操作,也被展开成与和或的组合等更长更复杂的表达式形式。另外还看到一些变形过的RC4,等等。不过因为我们已经是dump出来执行过的数据,所以必要的数据都已经解密了。如下图:
通过查看反编译的C代码,我发现程序中是直接通过JNI方法调用了Java中的bh类的方法a(在图2常量中也可以看到)。 再次回到dex层查看a方法,该方法是不断的将输入传递给不同的函数进行处理,先是cd的a方法,cC的a方法,p的a方法,x的a方法,ali$a的M$d方法(native),aS的a方法,x的a方法,ali$a的M&z方法(native),cd的a方法,cC的a方法,每一个方法都是些简单的数学运算,编码,以及密码学处理等可逆的操作,结合逆向和Indroid对输入输出的监控,都可以轻松确定每个Java函数的作用,具体过程如下代码显示:
invoke-static {}, LbKn;.a:()Z // method@08a1
move-result v3
invoke-static {v3}, LbKn;.b:(I)V // method@08a2
add-int/lit8 v0, v5, #int 1 // #01
invoke-static {v4, v5}, L.a:([BI)[B // method@0b23
move-result-object v1
add-int/lit8 v2, v0, #int 1 // #01
invoke-static {v1, v0}, LcC;.a:([BI)[B // method@0a30
move-result-object v0
add-int/lit8 v1, v2, #int -1 // #ff
invoke-static {v0, v2}, Lp;.a:([BI)[B // method@0e8d
move-result-object v0
invoke-static {v0, v1}, Lx;.a:([BI)[B // method@0ede
move-result-object v0
add-int/lit8 v2, v1, #int -1 // #ff
invoke-static {v0, v1}, Lali$a;.M$d:([BI)[B // method@03d3
move-result-object v0
add-int/lit8 v1, v2, #int 1 // #01
invoke-static {v0, v2}, LaS;.a:([BI)[B // method@022e
move-result-object v0
invoke-static {v0, v1}, Lx;.a:([BI)[B // method@0ede
move-result-object v0
add-int/lit8 v2, v1, #int 1 // #01
invoke-static {v0, v1}, Lali$a;.M$z:([BI)[B // method@0440
move-result-object v0
add-int/lit8 v1, v2, #int 1 // #01
invoke-static {v0, v2}, L.a:([BI)[B // method@0b23
move-result-object v0
add-int/lit8 v2, v1, #int 1 // #01
invoke-static {v0, v1}, LcC;.a:([BI)[B // method@0a30
move-result-object v0
return-object v0
值得注意的是,其中有两个native的方法,因为InDroid还可以监控调用native方法的参数以及返回值,我们发现这几个native都没有对输入做复杂的处理,只有M\$d对输入的第四个字节做了减8的处理。
做了这些逆变换以后我们其实并没有找到最终比较的处理,不过在解密过的数据中(图2),不仅有之前需要调用的各种方法和类,还可以发现有个十分可疑的Base64的字符串。
aJTCZnf6NyBPYJfbrBuLu0wOhRFbPtvqpYjiby5J81M=
并且在native的M\$z方法的反汇编代码中,可以看到有对这个Base64字符串的长度比较,由于我们并没有找到真正的比较函数,因此得到这个字符串后,我们直接从M\$z开始向上逆推之前的变换就得到了的答案。
具体解密代码如下:
#!/usr/bin/env python
# encoding: utf-8
from Crypto.Cipher import AES
def Lcda(s):
return &#39;&#39;.join(map(lambda x: chr((ord(x) + 3) & 0xff), s))
def de_Lcda(s):
return &#39;&#39;.join(map(lambda x: chr((ord(x) - 3) & 0xff), s))
def LcCa(s, a):
return &#39;&#39;.join([chr(((ord(s[i]) ^ a) + i) & 0xff) for i in xrange(len(s))])
def de_LcCa(s, a):
return &#39;&#39;.join([chr(((ord(s[i]) - i) & 0xff) ^ a) for i in xrange(len(s))])
def Lpa(s):
return s[1:] + s[0]
def de_Lpa(s):
return s[-1] + s[:-1]
def Lxa(s):
return s.encode(&base64&)[:-1]
def de_Lxa(s):
return s.decode(&base64&)
def LaliaMd(s):
return s[:3] + chr((ord(s[3]) - 8) & 0xff) + s[4:]
def de_LaliaMd(s):
return s[:3] + chr((ord(s[3]) + 8) & 0xff) + s[4:]
def LaSa(s):
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS)
cc = AES.new(&qqVJwt11yyLm7hVK1iI2aw==&.decode(&base64&), AES.MODE_ECB)
cipher = cc.encrypt(pad(s))
return cipher
def de_LaSa(s):
cc = AES.new(&qqVJwt11yyLm7hVK1iI2aw==&.decode(&base64&), AES.MODE_ECB)
cipher = cc.decrypt(s)
return cipher
res = &aJTCZnf6NyBPYJfbrBuLu0wOhRFbPtvqpYjiby5J81M=&
flag = de_Lcda(de_LcCa(de_Lpa(de_Lxa(de_LaliaMd(de_LaSa(de_Lxa(res))))), 49))
print flag
alilaba2345ba
这里还需要提一下如何寻找M\$d和M\$z两个函数在so库中的地址的方法,不过这个方法是一些经验的总结,原因是整个native ELF文件的节区结构是被修改过的。这两个方法和M\$j不太一样,因为在dump出的libmobisec里可以找到M\$z的函数名,证明这个方法没有使用RegiterNatives来做变换,因此我们可以通过符号表来找这个函数与文件头部的偏移。方法是找M\$z和字符串表的偏移,如0x03FE,然后穷搜整个文件:
因为符号表应该会把字符串表偏移作为一项,这块区域的结构体,我们对照ELF结构发现并不是标准的符号表,但还是可以大概看出结构体的内容,包括索引,字符串表偏移,以及ELF特殊的标志数,因此推测0x57BE4偏移是M\$z函数。该地址也正好是个压栈的指令,证明了我们的猜想。
2015年移动安全挑战赛的最后一道题目,在规定的比赛时间内,仅有来自我们GoSSIP的wbyang一名选手解决了这道问题,今天我们就来揭开这一道最高难度题目的神秘面纱。
先把名为AliCrackme_5.apk的文件丢到JEB里看一看:
dex文件并没有进行加壳和混淆,看上去是一个非常简单的程序,Java代码部分使用函数Register(&Bomb_Atlantis&, input)对输入进行判断。所以需要分析的逻辑应该都在libcrackme.so里的Register函数中。
接下来我们用IDA打开这个libcrackme.so,不出所料的发现IDA完全没法处理,应该是进行了强烈的混淆和加壳处理:
使用和解决前面题目相同的技巧,我们继续使用dd的方法来去处一部分的混淆和加壳。运行一次程序后,从/proc/self/maps里找到libcrackme.so在内存中的位置,使用dd命令从/proc/self/mem中提取出内存中的libcrackme.so,接着使用在解决第四题时使用过的技巧,将libcrackme.so和libc.so一起加载到IDA里。
用IDA打开dump出的代码后,我们发现仍然有大部分的代码无法被IDA识别,需要手动定位到需要分析的代码然后手工定义(IDA快捷键C)代码,同时由于代码会在THUMB指令集和ARM指令集之间切换,有时候需要用快捷键ALT+G来将T寄存器设置为不同的值,设置正确后才能正确翻译出代码。这里我们首先遇到的问题是无法定位Register函数,同样使用第四题中的技巧,用InDroid监控到Register函数的真实地址,就可以在该地址上开始分析。
在libcrackme.so这个动态库里使用的一些混淆方法,对于处理了前面一些类似混淆后现在的我们来说已经不是问题(^_^)。通过分析代码,我们定位了几个函数,这些函数的偏移在不同的设备上应该是不同的。整体的逻辑其实并不复杂,首先会有一个固定的字符串&Bomb_Atlantis&和一个固定的salt去进行一次md5运算,salt是动态生成的,不过由于dump内存的时候这些动态的值已经生成好了,所以能够直接发现这个salt(出于一些版权原因我们不便公布本题目的一些内部细节,因此该salt值请大家自己分析)
之后程序会将这个md5值和我们的输入进行一些异或和计算的操作,经过几步比较简单、可逆的变换之后,进入一个比较复杂的函数,经过这个函数处理后直接和一个内存中的值进行比较,返回比较结果。
这里说一个我们在做第五题时用到的分析方法&&动态hook。由于libcrackme.so中并没有对调用自身的上层应用进行验证,这就导致了我们可以自己写一个程序去加载这个so,调用其中的方法。这也导致了我们在加载libcrackme.so后,可以加载另一个用于hook的so,这样我们可以hook libcrackme.so中的任意函数,从而知道任意函数的参数和返回值,这对于我们理解程序有着非常大的帮助。这里我们使用的hook框架是著名安全研究人员Collin Mulliner开发的Android平台上的一个二进制注入框架adbi。当然这道题目并不能够通过注入的方法将我们的so注入进去,因为源程序禁掉了ptrace这样的调用。我们对adbi稍作修改,使之成为一个可以手动加载的动态hook框架。同时由于我们没法通过符号表来定位函数的地址,所有的hook地址都需要硬编码,并且要和运行这道题目程序的Android设备内存映射严格对应。
需要指出的是adbi中存在一个小bug,hook.c这个文件的118行应该是
h-&jumpt[0]=0x60
而不是0x30,对应的thumb汇编应该是
push{r5,r6}
push{r4,r5},
这个小bug在解题过程中会造成一些影响。使用adbi来hook这道题目的函数还需要注意一点,这题的代码中有一些函数使用的THUMB指令集,hook这些函数时,不要忘记人工的对hook地址+1。
通过hook的方法,我们已经能够动态的分析libcrackme.so,首先我们验证了我们对之前几步变换的分析结果。之后就是分析最后一个复杂的处理函数,通过静态分析+动态调试,我们发现这是一个类似于白盒密码学的加密函数。我们的输入进入函数后,首先经过几步类似DES的预处理,之后会进行若干轮的查表,通过查询一个巨大的表将我们的输入进行某种加密,生成一段密文,再经过几次简单的处理后和最后内存中的一段常量(出于一些版权原因我们不便公布本题目的一些内部细节,因此该常量请大家自己分析)进行比较。
通过动态调试,我们能够计算出加密算法最后应该输出的值,但是由于这个加密算法的密钥融入了整个置换表中,要找出一个逆置换表显然不太可能。我们简单过滤了libcrackme.so的其他函数,也没有发现用于解密的函数,想要正常解密密文是不太现实了。不过根据对加密算法的分析,我们发现这若干轮的置换是相互独立的,并且每一轮的复杂度并不高,这就意味这我们可以在可以接受的时间内对算法进行爆破。我们一开始的想法是code reuse,直接在Android设备上爆破,但是发现速度太慢,最后只能用笨办法,通过hook从内存中dump出来置换表,用C代码重写了这个算法,有惊无险地在比赛结束前半小时搜索出结果。根据逆推算法推出正确输入是:
3EFoAdTxepVcVtGgdVDB6AA=&&

我要回帖

更多关于 xms128m xmx512m 的文章

 

随机推荐