送给最好的ta逆向分析

本文最后更新于:2022年12月10日 上午

送给最好的ta逆向分析

1
2
3
4
5
6
7
文件名:送给最好的ta.apk
CRC32: 31C62FAD
MD5: 9819F3FA458129D7CA092C32839B7F38
SHA1: A948ACADD5647FF44E120CC6789BE7D8CCA59660
SHA256: 205160694C6D86C3056AAA2FB196B485CFA2A8A2F9F08BA966BE03B9EBFD936A
下载地址:https://www.123pan.com/s/07yA-W504 提取码:G5ob
注:这是原版app,请不要在公共场合运行,后果自负,概不负责。

分析安卓源码

使用Android Killer对软件进行逆向分析,我们可以看待内置了一个0.mp3这个应该就是循环播放的音频。

image-20221211145047788

打开init.luamain.lua发现是乱码,可能存在加密。

我们来手动反编译一下apk,获得原始文件,使用dex2jar工具生成jar文件。

1
java -jar apktool.jar d App.apk
1
d2j-dex2jar.bat classes.dex

使用jd-gui可以查看其java源码。

image-20221213140220539

可以看到存在com.androluacom.nirenrcomluajava等包名,搜索相关内容可以发现大部分app代码均来自于**AndroLua_pro**,可以猜测应该是使用了AndroLua_pro框架,AndroLua_pro是一个基于LuaJava开发的安卓平台轻量型的脚本编程语言工具。

通过搜索项目文件,最终在com.luajava.LuaState发现了引用动态链接库的代码,最终动态链接库会在lib/arm/目录中搜索。

image-20221213214006292

反编译动态链接库

AndroLua_Pro所使用的Lua工具LuaJava会加载依赖库libluajava.so,我们使用IDA逆向分析该文件。LuaJava通常会使用luaL_loadbuffer或者luaL_loadbufferx函数对Lua进行加载,此处也是加入Lua解密代码常见位置。

image-20221213145938465

但是IDA反编译似乎出现了一些问题,在汇编语言中存在变量异或操作,但是IDA反编译后,异或操作却消失了。

image-20221213150038234

这里我们使用了Ghidra重新进行反汇编可以看到相应加密代码。

image-20221213221053495

通过上面的分析很容易就可以看出这是一个异或加密,简单写一个解密脚本,找了好多解密代码,似乎都有问题不知道啥情况,先这样吧懒得搞了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# -*- coding:utf8 -*-
__author__='[email protected]'
__blog__='http://pcat.cc'

from ctypes import *
import sys

def decrypt(filename):
s=open(filename,'rb').read()
outfile='decode_'+ filename
if s[0]==chr(0x1b) and s[1]!=chr(0x4c):
rst=chr(0x1b)
size=len(s)
v10=0
for i in range(1,size):
v10+=size
v=(c_ulonglong(-2139062143*v10).value>>32)+v10
v1=c_uint(v).value>>7
v2=c_int(v).value<0
rst+=chr(ord(s[i])^(v10+v1+v2)&0xff)
with open(outfile,'wb') as f:
f.write(rst)
else:
pass

def foo():
if len(sys.argv)==2:
filename=sys.argv[1]
else:
filename='main.lua'
decrypt(filename)

if __name__ == '__main__':
foo(

安卓动态调试

这里我们也可以通过安卓程序动态调试直接从内存中获得解密的lua脚本。

注:太复杂了,放弃

重新打包apk

首先我们先将0.mp3替换成其他文件,防止社死。。。,之后使用apktool重新打包。

1
java -jar apktool.jar b APK

命令执行成功后,会在APK目录下会生成builddist目录:

  • build目录下存放的是打包后的dex文件和资源文件(和apk解压后一样一样的)
  • dist目录下存放的是重新打包后的apk文件

使用autosign重新签名

签名apk,重新发布,接下来就要用到签名工具signapk.jar了,如果不经过签名是不能正确运行的。

1
signapk.bat APK.apk APK_sign.apk

image-20221214111106732

反编译lua脚本

接下来我们反编译lua字节码

1
2
java -jar unluac.jar decode_init.lua >init-decomp.lua
java -jar unluac.jar decode_main.lua >main-decomp.lua

查看init.lua,代码的用途是声明应用基本信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local L0_0
appname = "\233\128\129\231\187\153\230\156\128\229\165\189\231\154\132TA"
appver = "1.0"
appcode = "10"
appsdk = "15"
path_pattern = ""
packagename = "com.sgzh.dt"
theme = "Theme_DeviceDefault_Dialog_NoActionBar_MinWidth"
app_key = ""
app_channel = ""
developer = ""
description = ""
debugmode = false
L0_0 = {
"INTERNET",
"WRITE_EXTERNAL_STORAGE"
}
user_permission = L0_0

执行具体功能的代码main-decomp.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
require("import")
import("android.app.*")
import("android.os.*")
import("android.widget.*")
import("android.view.*")
import("android.view.View")
import("android.content.Context")
import("android.media.MediaPlayer")
import("android.media.AudioManager")
import("com.androlua.Ticker")
activity.getSystemService(Context.AUDIO_SERVICE).setStreamVolume(AudioManager.STREAM_MUSIC, 15, AudioManager.FLAG_SHOW_UI)
activity.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE)
m = MediaPlayer()
m.reset()
m.setDataSource(activity.getLuaDir() .. "/0.mp3")
m.prepare()
m.start()
m.setLooping(true)
ti = Ticker()
ti.Period = 10
function ti.onTick()
activity.getSystemService(Context.AUDIO_SERVICE).setStreamVolume(AudioManager.STREAM_MUSIC, 15, AudioManager.FLAG_SHOW_UI)
activity.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE)
end
ti.start()
function onKeyDown(A0_0, A1_1)
if string.find(tostring(A1_1), "KEYCODE_BACK") ~= nil then
activity.getSystemService(Context.AUDIO_SERVICE).setStreamVolume(AudioManager.STREAM_MUSIC, 15, AudioManager.FLAG_SHOW_UI)
end
return true
end

具体操作有:

  • 将系统音量调制最大
  • 隐藏系统状态和导航栏,进入全屏模式
  • 每10tick重复上述步骤
  • 屏蔽系统返回键
  • 循环播放音频文件0.mp3

参考链接

深入理解 System.loadLibrary

NSA开源逆向工具Ghidra入门使用教程

[Android] 「送给最好的 TA」App逆向与Lua脚本解密实例

Android应用程序签名系统的签名(SignApk.jar)


送给最好的ta逆向分析
https://genioco.github.io/2022/12/14/misc/送给最好的ta逆向分析/
作者
BadWolf
发布于
2022年12月14日
许可协议