简介
crackme_0x01
通过快捷按钮进入APK入口点进行分析,如下图所示:
入口点代码
-
代码解析
关键点MainActivity$1
-
代码解析
-
final MainActivity this$0和 final EditText val$edtTxt这两个字段是构造函数MainActivity$1(MainActivity p0,EditText p1)的参数,其中this$0是对包含它的外部类MainActivity的引用,val$edtTxt是一个EditText对象,可能是用户在界面上输入的文本框。并调用 super() 方法初始化其他类属性 -
onClick(View p0) 方法是View.OnClickListener接口的一部分,当用户点击时,它会被调用。在这个方法中,通过FlagGuard类的getFlag方法获取一个名为flag的字符串,并进行判断,如果flag不为null,那么创建一个AlertDialogBuilder 实例,将显示一个标题为"Congratulations!",内容为"The flag is: "加上返回字符串的对话框。否则,将显示一个标题为"Nope!",内容为"Wrong password -> No flag :))"的对话框。对于这两个对话框,都设置了PositiveButton,并且为这个按钮设置了点击事件处理器。这两个点击事件处理器是MainActivity$1$1和MainActivity$1$2,它们是MainActivity$1的子类,可能是用来处理点击"OK"按钮的事件
这里找到了关键判断方法getFlag,双击进入查看
关键点getFlag
-
代码内容
-
解析代码
-
成员变量: -
flag:一个用于存储解密的字符串的变量。 -
pad:一个包含小写字母的字符串,用于解密过程。 -
scr_flag:一个包含混淆字符的字符串,这些字符将被解密。 -
构造方法: -
当创建一个新的FlagGuard对象时,构造方法会初始化pad和scr_flag变量,并将flag变量设置为空字符串。 -
unscramble() 方法: -
一个私有方法,用于解码字符串。这个方法首先定义了一个 StringBuilder 对象 str,然后从"qw4r_q0c_nc4nvx3_0i01_srq82q8mx"字符串中遍历每个字符,将其与"abcdefghijklmnopqrstuvwxyz"字符串中的字符进行比较,计算它们在字母表中的位置,并将结果添加到 StringBuilder 对象 str 中。最后,返回 str 字符串。 -
getFlag(String p0) 方法: -
一个公共方法,用于获取 flag 字符串。这个方法首先检查参数 p0 是否等于 Data 类的 getData() 方法返回的字符串,如果是,则调用 unscramble() 方法解码字符串并返回结果;否则,返回 null。
修改判断
-
NOP
-
修改指令
查看getData
-
代码如下
-
代码分析
crackme_0x02
入口函数
关键点MainActivity$1
关键点getFlag
-
代码内容
-
代码解析
-
成员变量: -
c1: 一个整型变量。 -
c2: 一个双精度浮点型变量。 -
flag: 一个字符串变量,用于存储解密的标志。 -
pad: 一个字符串,包含小写字母,用于解密过程。 -
scr_flag: 一个字符串,包含混淆的字符,这些字符将被解密。 -
构造方法: -
当一个新的 FlagGuard 对象被创建时,构造方法会被调用。它会初始化 pad 和 scr_flag 变量,并将 flag 变量设置为空字符串。同时,它也会设置 c1 和 c2 的值。 -
unscramble() 方法: -
这是一个私有方法,用于解密 scr_flag。 -
它通过遍历 scr_flag 中的每个字符,然后查找该字符在 pad 中的位置,并用该位置减去一个固定值(这个值是通过一些复杂的计算得出的,包括 c1 和 c2 的乘积)来得到一个索引。然后使用此索引从 pad 中选择一个字符,并添加到结果字符串中。 -
如果字符在 pad 中找不到(即索引小于0),则直接将该字符添加到结果字符串中。 -
最后,该方法返回解密后的字符串。在整个过程中,该方法会使用 Log.e 打印一些调试信息。 -
getFlag(Context p0, String p1) 方法: -
这是一个公共方法,接受一个 Context 对象和一个字符串作为参数。 -
如果传入的字符串与另一个类(可能是 Data)的 getData(p0) 方法返回的字符串相同,则调用 unscramble() 方法并返回解密后的字符串。 -
如果传入的字符串不匹配,则返回null。
关键点getDate
-
成员变量: -
secret:这是一个私有字符串变量,它存储了一个秘密字符串。 -
构造方法: -
public void Data():这是类的构造方法,它没有参数。在这个方法中,调用了父类的构造方法(super()),并将secret初始化为一个空字符串。 -
方法: -
public String getData(Context p0):这是一个公共方法,它接收一个Context类型的参数,名为p0。这个方法从Context对象中获取字符串资源R.string.secret的值,并将其赋值给secret。然后返回secret的值。 -
这个资源文件的路径通常是在res/values/strings.xml
<string name="secret">s0m3_0th3r_s3cr3t_passw0rd</string>
crackme_0x03
入口函数
关键点MainActivity$1
关键点getFlag
-
代码解析
修改
关键点generate
-
代码解析
-
定义变量:定义了一些整数变量和 StringBuilder 变量。 -
创建整数数组:创建一个名为 ointArray1 的整数数组,其长度为 i(20),并用数组初始化列表初始化。 -
设置数组元素:将数组 ointArray1 的所有元素设置为 27。 -
判断条件:判断 Build$VERSION.CODENAME 的长度是否大于 0,如果大于 0,则执行以下操作;否则,执行第 9 行的代码。 -
循环:使用一个 while 循环,当 i2 小于 i3(5)时,执行循环体。在循环体内,根据 i2 的值进行不同的操作,包括设置数组元素、交换元素位置等。每次循环结束后,i2 自增 1。当 i2 大于等于 i3 时,跳出循环。 -
设置数组元素:将数组 ointArray1 的 i5(10)个元素设置为 73,将数组 ointArray1 的 13、12、i4(11)个元素分别设置为 79,将数组 ointArray1 的 7 个元素设置为 79 - 2。 -
循环:使用一个 while 循环,当 i2 小于 i(20)时,执行循环体。在循环体内,根据 i2 的值进行不同的操作,包括设置数组元素、交换元素位置等。每次循环结束后,i2 自增 1。当 i2 大于等于 i 时,跳出循环。 -
返回结果:返回 StringBuilder 变量 str 的值,即生成的字符串。
整个函数通过复杂的循环和条件语句,对整数数组进行了一系列操作,最终生成了一个包含特定字符的字符串。
关键点isPasswordOk
-
代码解析
-
类定义和静态代码块:定义了一个名为 Data 的类,同时定义了一个静态的 lastError 变量,默认为"Unknown error..."。 -
构造函数:Data 类的构造函数,设置了以下属性: -
short_password_message:密码太短的消息 -
long_password_message:密码太长的消息 -
wrong_password_message:输入错误的密码的消息 -
password_length:密码长度,默认为 6 -
password_hash:用于验证密码的 MD5 哈希值,默认为 "ac43bb53262e4edd82c0e82a93c84755" -
MD5Compare 方法:用于比较两个字符串的 MD5 哈希值是否相等。如果相等,返回 true;否则返回 false。 -
getData 方法:返回 Data 类的 MD5 哈希值,即"ac43bb53262e4edd82c0e82a93c84755" -
getLastError 方法:返回 lastError 变量的值,用于显示最后一个错误信息
往期推荐
原文始发于微信公众号(白帽子):原创 | GDA CTF应用方向:牛刀小试ONE
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论