GDA CTF应用方向:牛刀小试ONE
本帖最后由 梦幻的彼岸 于 2023-10-9 14:46 编辑简介首发:https://sec-in.com/article/2269作者:梦幻的彼岸测试程序来源:https://github.com/num1r0/android_crackmes本篇文章涉及工具:GDAcrackme_0x01通过快捷按钮进入APK入口点进行分析,如下图所示:https://bbs.kanxue.com/upload/attach/202310/767964_396RKXEG4BY4W8D.webp入口点代码https://bbs.kanxue.com/upload/attach/202310/767964_QZ3VZDFYE2NUEQP.webp
[*]代码解析
这段代码定义了一个名为MainActivity的Android应用程序类,它继承自AppCompatActivity。此类中定义了两个私有字段,name和description,分别用于存储应用程序的名称和描述。MainActivity的构造函数中,对这两个字段进行了初始化。follow_clicked方法用于处理点击事件,它尝试打开一个指向特定Twitter用户的链接。如果第一种方式失败,它会尝试使用另一种方式打开链接。onCreate方法是Android应用程序的生命周期方法之一,在应用程序启动时运行。在这个函数中,隐藏了应用程序的ActionBar,设置了应用程序的布局,并设置了一个点击监听器,当用户点击'submit'按钮时,会执行MainActivity$1类的实例的onClick方法。
关键点MainActivity$1https://bbs.kanxue.com/upload/attach/202310/767964_QQMTT2PZ5SC3JX8.webp代码内容https://bbs.kanxue.com/upload/attach/202310/767964_NMCN7THVTD7CRB6.webp
[*]代码解析
这段代码是一个名为MainActivity$1的Java的匿名内部类,它实现了View$OnClickListener接口,这个接口是Android开发中用于处理点击事件的。分析一下这个类的各个部分:
[*]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
[*]代码内容
https://bbs.kanxue.com/upload/attach/202310/767964_JB3RCCJ4UTAHEUU.webp
[*]解析代码
这段代码定义了一个名为FlagGuard的Java类,它具有以下功能:
[*]成员变量:
[*]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。
又看到关键点了用来判断并输出内容,思路,更改判断不输出null,或查看getData方法涉及内容以查找对比的字符串很多概率就是flag修改判断现在修改位置右键点击切换代码功能https://bbs.kanxue.com/upload/attach/202310/767964_7NXC227HSNXTPXR.webpsmail代码https://bbs.kanxue.com/upload/attach/202310/767964_6T978S5R5QBJCZM.webp这里两个思路一个是NOP填充判断或修改判断指令将if-eqz修改为if-nez两种修改思路都演示下
[*]NOP
在要NOP的位置右键点NOP按钮https://bbs.kanxue.com/upload/attach/202310/767964_92XWJQKG2SWWJ8Z.webp修改后的效果https://bbs.kanxue.com/upload/attach/202310/767964_NHQNEA8J6EB8F3Z.webp此时按r键保存修改https://bbs.kanxue.com/upload/attach/202310/767964_Z6X66EUTGDNG44Z.webp点击OK进行之后的安装测试步骤选择链接的设备https://bbs.kanxue.com/upload/attach/202310/767964_KZP64K5W6PNQQS3.webphttps://bbs.kanxue.com/upload/attach/202310/767964_35NAT7AYB9DXBFT.webp安装完毕https://bbs.kanxue.com/upload/attach/202310/767964_WQMZ7MCZ6UW5P9Z.webphttps://bbs.kanxue.com/upload/attach/202310/767964_G32Z7Y463VTZQC9.webp输入测试https://bbs.kanxue.com/upload/attach/202310/767964_HZZ33SQB7EBHJ8F.webp弹出了flaghttps://bbs.kanxue.com/upload/attach/202310/767964_MBQBW8Y56AMQD8Z.webp
[*]修改指令
因之前NOP填充过,此时需要恢复DEX数据重新加载https://bbs.kanxue.com/upload/attach/202310/767964_5DUBADRSFYAH9QN.webp恢复并重新加载后https://bbs.kanxue.com/upload/attach/202310/767964_C497UZ73FE4H24N.webp在要修改的位置按M进入修改模式或右键修改指令功能https://bbs.kanxue.com/upload/attach/202310/767964_HFMUGR555E6MSMT.webp回车确定修改后的效果https://bbs.kanxue.com/upload/attach/202310/767964_RRG4XS6XZ6RE8FX.webp这里解析下if-nez: 对比如果不相等则跳转if-eqz: 对比如果相等则跳转这里修改为if-nez后达到输入错误的flag导致对比不先等以输出内容的目的保存安装测试https://bbs.kanxue.com/upload/attach/202310/767964_T6AENAXBW3C4YXH.webp同样获取到flag查看getDatagetData位置双击
[*]代码如下
https://bbs.kanxue.com/upload/attach/202310/767964_7CDJD7RDTQJPW5M.webp
[*]代码分析
这是一个名为 Data 的 Java 类,它包含一个私有权限的 String 类型的变量 secret,以及两个公共方法:Data() 构造函数和 getData() 方法,但是,getData 方法并没有返回 secret 字段的值,而是返回了一个硬编码的字符串("s3cr37_p4ssw0rd_1337")。前后分析,这个字符串就是对比的关键了修改判断apk测试https://bbs.kanxue.com/upload/attach/202310/767964_42PDSBUH28CQT7E.webp看这样就是关键内容了,和正确的结果对比返回了错误的数据,安装未修改apk验证https://bbs.kanxue.com/upload/attach/202310/767964_QW669N57Z67E3YD.webp验证成功
crackme_0x02入口函数同样的方法入口点查看https://bbs.kanxue.com/upload/attach/202310/767964_VJ78KPBAXT9SUT5.webp这里代码和之前类似就不讲解了关键点MainActivity$1https://bbs.kanxue.com/upload/attach/202310/767964_HE4FNCY8YVRS64H.webp这里代码和之前类似就不讲解了关键点getFlag
[*]代码内容
https://bbs.kanxue.com/upload/attach/202310/767964_7GMV69SMKEPP3QY.webp
[*]代码解析
这段代码定义了一个名为 FlagGuard 的Java类。以下是对这个类的详细解析:
[*]成员变量:
[*]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。
同样思路测试https://bbs.kanxue.com/upload/attach/202310/767964_PJE9F4V82DQTGAJ.webphttps://bbs.kanxue.com/upload/attach/202310/767964_HQNYYT298H2WHYP.webp轻松获得flag关键点getDatehttps://bbs.kanxue.com/upload/attach/202310/767964_6V7R9BS7GE67H7T.webp这段 Java 代码定义了一个名为Data的类,位于com.entebra.crackme0x02.Data包中。该类有以下内容:导入了一些所需的类:java.lang.Object:继承自 Java 的基类Object。android.content.Context:表示 Android 应用程序中的上下文对象,用于访问应用程序的资源。java.lang.String:表示 Java 中的字符串类型。
[*]成员变量:
[*]secret:这是一个私有字符串变量,它存储了一个秘密字符串。
[*]构造方法:
[*]public void Data():这是类的构造方法,它没有参数。在这个方法中,调用了父类的构造方法(super()),并将secret初始化为一个空字符串。
[*]方法:
[*]public String getData(Context p0):这是一个公共方法,它接收一个Context类型的参数,名为p0。这个方法从Context对象中获取字符串资源R.string.secret的值,并将其赋值给secret。然后返回secret的值。
[*]这个资源文件的路径通常是在res/values/strings.xml
https://bbs.kanxue.com/upload/attach/202310/767964_877FNM7YENGYUHJ.webp
<string name="secret">s0m3_0th3r_s3cr3t_passw0rd</string>
验证https://bbs.kanxue.com/upload/attach/202310/767964_DUKZGZEFV9DA25H.webpcrackme_0x03入口函数同样通过快捷按键进入https://bbs.kanxue.com/upload/attach/202310/767964_GM57B79ZQ3AYWEA.webp关键点MainActivity$1https://bbs.kanxue.com/upload/attach/202310/767964_86PQ6WQG2ASJQM8.webp关键点getFlaghttps://bbs.kanxue.com/upload/attach/202310/767964_33KCG3RJZKJYTG3.webp
[*]代码解析
这段 Java 代码定义了一个名为 FlagGuard 的类。该类包含一个名为 flag 的字符数组,以及一个名为 generate 的私有方法。generate 方法的主要目的是生成一个字符串,该字符串基于输入的字符串 p0(在 getFlag 方法中使用)。首先,代码导入了所需的类,如 Object、String、StringBuilder 和 android.os.Build$VERSION 等。 接下来,FlagGuard 类的构造函数创建了一个名为 uocharArray 的字符数组,并将其赋值给 this.flag。generate 方法开始时,定义了几个整数变量,然后创建了一个名为 ointArray 的整数数组。接着,创建了一个名为 str 的字符串构建器,用于存储生成的字符串。同时,创建了一个名为 ointArray1 的整数数组,用于在后续的循环中进行操作。在 if 语句中,检查 Build$VERSION.CODENAME 的长度是否大于 0。如果满足条件,将执行一个 while 循环。在循环中,对 ointArray1 数组的元素进行了一系列操作,如赋值、移位、相加等。这些操作的具体目的尚不明确,可能与生成字符串有关。在另一个 if 语句中,如果输入字符串 p0 满足 Data 类的 isPasswordOk 方法,则调用 generate 方法生成字符串。在 generate 方法中,首先检查输入字符串 p0 是否满足条件。如果满足,将执行一个 for 循环,遍历整数数组 ointArray,并将每个元素的值存储在 flag 数组中。最后,将 flag 数组拼接到字符串构建器 str 中,并返回结果。总之,这段代码的主要目的是生成一个字符串,该字符串可能与密码验证有关。具体的生成逻辑涉及到一系列复杂的数学运算,但具体含义尚不明确。总结:可修改判断或查看 generate 方法生成字符串或isPasswordOk内容修改https://bbs.kanxue.com/upload/attach/202310/767964_N6WQ5MQ9982UHUZ.webp轻松获取flaghttps://bbs.kanxue.com/upload/attach/202310/767964_7MWSPJSK64W5HSK.webp关键点generatehttps://bbs.kanxue.com/upload/attach/202310/767964_VSDMZ9MNQVGS5S5.webp
[*]代码解析
这段 Java 代码的主要功能是生成一个字符串,其中包含一个整数数组和一些特定的操作。以下是代码的详细解析:
[*]定义变量:定义了一些整数变量和 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 的值,即生成的字符串。
整个函数通过复杂的循环和条件语句,对整数数组进行了一系列操作,最终生成了一个包含特定字符的字符串。
关键点isPasswordOkhttps://bbs.kanxue.com/upload/attach/202310/767964_KF34YPTV5YNVJ6U.webp
[*]代码解析
这段 Java 代码定义了一个名为 Data 的类,主要用于处理密码验证。以下是代码的解析:
[*]类定义和静态代码块:定义了一个名为 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 变量的值,用于显示最后一个错误信息
看了这里要通过反解md5来获取关键信息https://bbs.kanxue.com/upload/attach/202310/767964_ZYPBYG4JMJ93DN9.webp
牛逼了表格 表哥牛逼啊,顶起来 牛了个逼,表哥 很详细的教程,谢谢! 牛了个逼,表哥 牛了个逼,表哥 牛逼的表哥 。 牛逼的表哥 ,来一发GDA PRO版本吧 感谢大佬分享
页:
[1]
2