进击的Android注入术《二》

继续

在《一》里,我把基本思路描写叙述了一遍,接下为我们先从注入開始入手。

注入

分类

我们平时所说的代码注入,主要静态和动态两种方式

  • 静态注入,针对是可运行文件,比方平时我们改动ELF,DEX文件等等,相关的辅助工具也非常多,比方IDA、JEB、ApkTool等等;
  • 动态注入,针对是进程,比方改动进程的寄存器、内存值等等;

动态跟静态最大的差别是,动态不须要修改源文件,但须要高权限(一般是root权限),并且所需的技术含量更高。

本质

动态注入技术,本质上就是一种调度技术。想想平时我们调试一个进程时,能够做哪些功能? 一般有下列几项:

  • 查看变量值
  • 改动变量值
  • 跟踪进程跳转
  • 查看进程调用堆栈
  • 等等

动态注入相比于普通的调试,最大的差别就是动态注入是一个”自己主动化调试并达到载入自己定义动态链接库“的过程。所谓自己主动化,事实上就是通过代码实现,在Linux上通过Ptrace就能够完毕上面全部功能,当然Ptrace功能是比較原始的,平时调试中的功能还须要非常多高层逻辑封装才干够实现。

在阅读以下章节之前,强烈建议阅读一下man文档,见这里

目的

一般而言,我们要对一个进程进行注入,主要有下面几方面目的:

  • 增强目标进程的功能;
  • 修复目标进程缺陷;
  • 劫持目标进程函数;
  • 窃取目标进程数据;
  • 篡改目标进程数据;

过程

如上图所看到的,进程A注入到进程B后,通过改动寄存器和内存,让进程B载入自己定义的动态库a,当a被载入后,a会尝试载入其它模块,比方载入dex文件等等,详细的注入步骤例如以下:

  • ATTATCH,指定目标进程,開始调试;
  • GETREGS,获取目标进程的寄存器,保存现场;
  • SETREGS,改动PC等相关寄存器,使其指向mmap;
  • POPETEXT,把so path写入mmap申请的地址空间;
  • SETRESG,改动PC等相关寄存器,使其指向dlopen;
  • SETREGS,恢复现场;
  • DETACH,解除调试,使其恢复;

上述是一个简化的过程,整个注入的代码,我已经上传到github,地址https://github.com/boyliang/Poison

当so被dlopen载入到目标进程后,我们须要让so中的逻辑被运行,比較复杂的做法是相同使用ptrace改动寄存器的办法,让目标进程调用dlsym找到我们函数的地址。而比較简单的做法有两种,例如以下

  • 使用gcc的预编译指令__attribute__ ((__constructor__)),作用是让so被载入后,函数被自己主动运行;
__attribute__ ((__constructor__))
void Main() {
 LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<");

 void* handle = dlopen("libinso.so", RTLD_NOW);
 void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA");

 if (setA_func) {
   setA_func(999);
 }
}
  • 使用c++全局对象初始化,其构造函数会被自己主动运行;
void Main();

static void* _main(void*){
	Main();
	return NULL;
}

class EntryClass {
public:

	EntryClass() {
		pthread_t tid;
		pthread_create(&tid, NULL, _main, NULL);
		pthread_detach(tid);
	}

} boy;

演示样例一

以下演示样例一个通过ptrace注入的演示样例,涉及到两部分代码,一部分是目标进程代码记作host,还有一部分是被我们注入的so代码记作libmyso.so

Host代码

包括三个源文件,各自是demo1.c,inso.h, inso.c

/*
 * inso.h
 *
 *  Created on: 2014年6月24日
 *      Author: boyliang
 */

__attribute__ ((visibility ("default"))) void setA(int i);

__attribute__ ((visibility ("default"))) int getA();
/*
 * inso.c
 *
 *  Created on: 2014年6月24日
 *      Author: boyliang
 */

#include <stdio.h>
#include "inso.h"

static int gA = 1;

void setA(int i){
	gA = i;
}

int getA(){
	return gA;
}
/*
 * demo1.c
 *
 *  Created on: 2014年6月24日
 *      Author: boyliang
 */

#include <stdio.h>
#include <unistd.h>

#include "inso.h"
#include "log.h"

int main(){

	LOGI("DEMO1 start.");

	while(1){
		LOGI("%d", getA());
		setA(getA() + 1);
		sleep(2);
	}

	return 0;
}

libmyso.so代码

/*
 * myso.c
 *
 *  Created on: 2014年6月24日
 *      Author: boyliang
 */

#include <stdio.h>
#include <stddef.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stddef.h>

#include  "log.h"

__attribute__ ((__constructor__))
void Main() {
	LOGI(">>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<");

	void* handle = dlopen("libinso.so", RTLD_NOW);
	void (*setA_func)(int) = (void (*)(int))dlsym(handle, "setA");

	if (setA_func) {
		setA_func(999);
	}
}

调用

注入程序,我将其命名为poison,用法是poison <so_path> <target_pit>。以下是演示样例的输出显示:

I/TTT     (  594): DEMO1 start.
I/TTT     (  594): 1
I/TTT     (  594): 2
I/TTT     (  594): 3
I/TTT     (  594): 4
I/TTT     (  594): 5
I/TTT     (  594): 6
I/TTT     (  594): 7
I/TTT     (  594): >>>>>>>>>>>>>I am in, I am a bad boy 1!!!!<<<<<<<<<<<<<<
I/TTT     (  594): 999
I/TTT     (  594): 1000
I/TTT     (  594): 1001

当运行./poison /data/local/tmp/libmyso.so 594后,输出中立即出现了特定字符串,而且打印的数据一下子变成了999,证明我们注入成功了。

演示样例代码

上述演示样例所涉及到代码,我都放公布到github上了,大家假设想研究代码,能够到https://github.com/boyliang/injection_by_ptrace

《三》,我会再介绍一种Android上特有的注入技术,敬请期待。

时间: 2024-10-15 10:31:12

进击的Android注入术《二》的相关文章

Android 注入详解

Android下的注入的效果是类似于Windows下的dll注入,关于Windows下面的注入可以参考这篇文章Windows注入术.而Android一般处理器是arm架构,内核是基于linux,因此进程间是弱相互作用,不存在Windows下类似于CreateRemoteThread 作用的函数,可以在其他进程空间内创建线程来加载我们的.so文件,所以我们所采用的方法就是依赖于linux下的ptrace()函数,将目标进程作为我们进程的子进程操作目标进程的寄存器和内存来运行我们加载.so文件的代码

Android注入完全剖析

0 前沿 本文主要分析了一份实现Android注入的代码的技术细节,但是并不涉及ptrace相关的知识,所以读者如果不了解ptrace的话,最好先学习下ptrace原理再来阅读本文.首先,感谢源代码的作者ariesjzj大牛,没有他的源码就没有本文~.文中有不对的地方,望各位大牛斧正!谢谢~ 相关代码下载地址: http://pan.baidu.com/s/1o6ul8eA 或者去代码原作者的blog: http://blog.csdn.net/jinzhuojun/article/detail

GitHub上不错的Android开源项目(二)

收集相关系列资料,自己用作参考,练习和实践.小伙伴们,总有一天,你也能写出 Niubility 的 Android App :-) 系列文章如下: GitHub上不错的Android开源项目(一):http://www.cnblogs.com/haochuang/p/4676090.html GitHub上不错的Android开源项目(二):http://www.cnblogs.com/haochuang/p/4676092.html GitHub上不错的Android开源项目(三):http:

小白日记44:kali渗透测试之Web渗透-SqlMap自动注入(二)-sqlmap参数详解REQUEST

Sqlmap自动注入(二) Request ################################################### #inurl:.php?id= 1. 数据段:--data Get/post都使用 [POST方法]Sqlmap -u "http://1.1.1.1/a.php" --data="user=1&pass=2" –f #sqlmap可自动识别"&" [GET方法]Sqlmap –u &

Android学习Scroller(二)——ViewGroup调用scrollTo()

MainActivity如下: package cc.ac; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.app.Activity; /** * Demo描述: * 对ViewGroup调用sc

android binder 机制二(client和普通server)

在讲它们之间的通信之前,我们先以MediaServer为例看看普通Server进程都在干些什么. int main() { -- // 获得ProcessState实例 sp<ProcessState> proc(ProcessState::self()); // 得到ServiceManager的Binder客户端实例 sp<IServiceManager> sm = defaultServiceManager(); -- // 通过ServiceManager的Binder客户

详解Android ActionBar之二:ActionBar添加Tabs标签和下拉导航

本节主要讲解ActionBar如何添加Tabs标签和下拉导航. 一.添加标签 Tabs 在ActionBar中实现标签页可以实现android.app.ActionBar.TabListener ,重写onTabSelected.onTabUnselected和onTabReselected方法来关联Fragment.代码如下: Java代码 private class MyTabListener implements ActionBar.TabListener { private TabCon

Android学习Scroller(二)

MainActivity如下: package cc.testscroller1; import android.app.Activity; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.view.View.OnClick

Android之十二微信UI界面设计

Android之十二微信UI界面设计 corners_bg.xml <span style="font-size:14px;"><?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color=&qu