首页
社区
课程
招聘
[原创]CTF黑客精神:算法还原
发表于: 2023-12-8 00:51 10249

[原创]CTF黑客精神:算法还原

2023-12-8 00:51
10249

这题的解法有很多,可以通过so文件的静态分析,直接将结果写入文件达到解题的目的,不过核心思想肯定是希望我们通过逆向他的算法来获取flag.接下来我将详细的分析算法逆向的过程。

图片描述

打开APP先简单试玩下,发现点击不玩了或者注册码填写错误提交都会发生闪退,把代码拖入到jadx中。我们从代码找到注册页面。
图片描述

通过代码可以看出,他的flag核心代码在libmyjni.so里面,调用了这iniSN()、saveSM()、work()这三个函数。在分析so文件之前,我们先解决闪退的问题,关键代码 Process.killProcess(Process.myPid());通过frida hook修改其逻辑。

将APK解压,找到目标文件,拖入到IDA中,一眼看去并没有发现iniSN()、saveSM()、work()这个三个函数。
图片描述
接着我们去JNI_OnLoad中去定位,找到他的伪C代码。
图片描述
这段代码是一个 JNI(Java Native Interface)的实现,用于在Java虚拟机加载本地库时执行。然后主要看这段代码:

RegisterNatives 用于将本地方法与 Java 类关联起来。off_5004 是一个本地方法数组,包含要注册的本地方法的信息。这里注册了3个本地方法。在进入到off_5004后。如图所示,我们来理解下这段汇编代码。
aInitsn: 字符串,表示第一个本地方法的名字为 "initSN"
aV: 字符串,表示第一个本地方法的签名,这里是 "()V",表示无参数无返回值的方法。
n1+1: 指向 initSN 本地方法的实现函数的地址。
那么以此类推:
n1 = iniSN()
n2 = saveSM()
n3 = work()
这个时候思路就非常清晰了,先来看下这三个函数的代码:
图片描述
n1这个函数的执行逻辑:
打开一个文件 /sdcard/reg.dat,读取文件内容,与指定的字符串进行比较,然后通过调用 setValue 函数将结果写入内存中。最后,关闭文件并返回 fclose 函数的结果。
n2这个函数的执行逻辑:
读取指定文件中的内容,对内容进行异或加密,然后将加密后的内容写回文件中。密钥是根据字符串 "W3_arE_whO_we_ARE" 计算得到的。
n3这个函数的执行逻辑:
他再次调用了n1函数,调用 getValue 函数的值,来判断该返回什么样的内存。返回值有&unk_2E6B、&unk_2E95、&unk_2E5B。我们点进去按A。
图片描述
很明显Value = getValue(a1) ==1 是我想要的结果。再回过头看n1函数。想要等于1就要满足

他又是从文件/sdcard/reg.dat文件取出来的,那问题来了,他又是怎么存的呢?n2函数里面的 :

代码逻辑是输入的值存进去的。再综合整理下代码的执行逻辑。
输入的值等于EoPAoY62@ElRD,再完成加密,保持EoPAoY62@ElRD到/sdcard/reg.dat文件中,再调用n3 (n1 里面满足了条件,设置1值)得到value=1.结束。

目标就是输入的值经过加密等于: EoPAoY62@ElRD 就得出flag

通过上面的分析他的核心算法在n2中。
图片描述

通过分析发现他是将我们输入的值和给定的值进行异或操作。然后我们用python 进行算法还原:

将结果201608Am!2333输入到APP中:
当再次打开的是时候出现:如下。
图片描述

function hook_d(){
    Java.perform(function(){
        var process_class =  Java.use("android.os.Process");
        process_class['killProcess'].implementation = function(pid){
            this['killProcess'](444);//或者注释掉,不调用这个也行
        }
    })
}
function hook_d(){
    Java.perform(function(){
        var process_class =  Java.use("android.os.Process");
        process_class['killProcess'].implementation = function(pid){
            this['killProcess'](444);//或者注释掉,不调用这个也行
        }
    })
}
if ( !(*g_env)->RegisterNatives(g_env, (jclass)native_class, (const JNINativeMethod *)off_5004, 3) )
if ( !(*g_env)->RegisterNatives(g_env, (jclass)native_class, (const JNINativeMethod *)off_5004, 3) )
strcmp((const char *)v6, "EoPAoY62@ElRD") )
strcmp((const char *)v6, "EoPAoY62@ElRD") )
fputs(v16, v5);// 将加密后的内容写入文件
fputs(v16, v5);// 将加密后的内容写入文件
from urllib import parse
 
v7 = "EoPAoY62@ElRD"
v8 = bytearray(v7, 'utf-8')
v13 = "W3_arE_whO_we_ARE"
v12 = len(v7)
v9 = 2016
v10 = 0
while v10 < v12:
    if v10 % 3 == 1:
        v9 = (v9 + 5) % 16
        v11 = ord(v13[v9 + 1])
    elif v10 % 3 == 2:
        v9 = (v9 + 7) % 15
        v11 = ord(v13[v9 + 2])
    else:
        v9 = (v9 + 3) % 13
        v11 = ord(v13[v9 + 3])
 
    v8[v10] ^= v11
    v10 += 1
 
decrypted_bytes = bytes(v8)
print(decrypted_bytes.decode('utf-8')) //201608Am!2333
from urllib import parse

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 8
支持
分享
最新回复 (4)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2023-12-8 10:26
1
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
谢谢楼主分享
2023-12-8 14:08
0
雪    币: 833
活跃值: (815)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享。不过不太建议用什么”黑客“精神来标签。黑客也不是啥好词。 
2023-12-14 15:22
0
雪    币: 70
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
adream2000 感谢分享。不过不太建议用什么”黑客“精神来标签。黑客也不是啥好词。
黑帽子黑客是坏人,白帽子黑客是好人
2023-12-17 12:08
0
游客
登录 | 注册 方可回帖
返回
//