Dalvik解释器源码到VMP分析
本文为看雪论坛优秀文章
看雪论坛作者ID:glider菜鸟
dalvik解释器解释指令前的准备工作
dalvik解释器的模型
invoke-super指令实例分析
解释器解释指令前的准备工作
解释器的模型
invoke-super指令实例分析
dalvik解释器解释指令前的准备工作
dvmCallMethod -> dvmCallMethodV -> dvmInterpret
dvmCallMethodV
1. 取出函数的简单声明,如onCreate函数的简单声明为:VL
2. 分配虚拟寄存器栈
3. 放入this参数,根据参数类型放入申明中的参数
4. 如果方法是native方法,直接跳转到method->nativeFunc执行
5. 如果方法是java方法,进入dvmInterpret解释执行
void dvmCallMethodV(Thread* self, const Method* method, Object* obj, bool fromJni, JValue* pResult, va_list args)
{
//取出方法的简要声明
const char* desc = &(method->shorty[1]); // [0] is the return type.
int verifyCount = 0;
ClassObject* clazz;
u4* ins;
//访问权限检查,以及分配函数调用栈,在栈中维护了一份虚拟寄存器列表。
clazz = callPrep(self, method, obj, false);
if (clazz == NULL)
return;
/* "ins" for new frame start at frame pointer plus locals */
//指向第一个参数
ins = ((u4*)self->interpSave.curFrame) + (method->registersSize - method->insSize);
//放入this指针,到第一个参数。
/* put "this" pointer into in0 if appropriate */
if (!dvmIsStaticMethod(method)) {
*ins++ = (u4) obj;
verifyCount++;
}
//根据后续参数的类型,放入后续参数
while (*desc != '\0') {
switch (*(desc++)) {
case 'D': case 'J': {
u8 val = va_arg(args, u8);
memcpy(ins, &val, 8); // EABI prevents direct store
ins += 2;
verifyCount += 2;
break;
}
case 'F': {
/* floats were normalized to doubles; convert back */
float f = (float) va_arg(args, double);
*ins++ = dvmFloatToU4(f);
verifyCount++;
break;
}
case 'L': { /* 'shorty' descr uses L for all refs, incl array */
void* arg = va_arg(args, void*);
assert(obj == NULL || dvmIsHeapAddress(obj));
jobject argObj = reinterpret_cast<jobject>(arg);
if (fromJni)
*ins++ = (u4) dvmDecodeIndirectRef(self, argObj);
else
*ins++ = (u4) argObj;
verifyCount++;
break;
}
default: {
/* Z B C S I -- all passed as 32-bit integers */
*ins++ = va_arg(args, u4);
verifyCount++;
break;
}
}
}
//如果是本地方法,就直接跳转到本地方法,若是java方法,进入解释器,解释执行。
if (dvmIsNativeMethod(method)) {
TRACE_METHOD_ENTER(self, method);
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)((u4*)self->interpSave.curFrame, pResult,
method, self);
TRACE_METHOD_EXIT(self, method);
} else {
dvmInterpret(self, method, pResult);
}
dvmPopFrame(self);
}
dvmInterpret
void dvmInterpret(Thread* self, const Method* method, JValue* pResult)
{
//解释器的状态
InterpSaveState interpSaveState;
ExecutionSubModes savedSubModes;
#if defined(WITH_JIT)
double calleeSave[JIT_CALLEE_SAVE_DOUBLE_COUNT];
#endif
//保存之前的解释器状态,并将新的状态和之前的状态连接起来(链表)
interpSaveState = self->interpSave;
self->interpSave.prev = &interpSaveState;
/*
* Strip out and save any flags that should not be inherited by
* nested interpreter activation.
*/
savedSubModes = (ExecutionSubModes)(
self->interpBreak.ctl.subMode & LOCAL_SUBMODE);
if (savedSubModes != kSubModeNormal) {
dvmDisableSubMode(self, savedSubModes);
}
#if defined(WITH_JIT)
dvmJitCalleeSave(calleeSave);
#endif
#if defined(WITH_TRACKREF_CHECKS)
self->interpSave.debugTrackedRefStart =
dvmReferenceTableEntries(&self->internalLocalRefTable);
#endif
self->debugIsMethodEntry = true;
#if defined(WITH_JIT)
/* Initialize the state to kJitNot */
self->jitState = kJitNot;
#endif
/初始化解释器的执行环境
self->interpSave.method = method; //初始化执行的方法
self->interpSave.curFrame = (u4*) self->interpSave.curFrame; //初始化函数调用栈
self->interpSave.pc = method->insns; //初始化程序计数器
//检查方法是否为本地方法
assert(!dvmIsNativeMethod(method));
//方法的类是否初始化
if (method->clazz->status < CLASS_INITIALIZING || method->clazz->status == CLASS_ERROR)
{
ALOGE("ERROR: tried to execute code in unprepared class '%s' (%d)",
method->clazz->descriptor, method->clazz->status);
dvmDumpThread(self, false);
dvmAbort();
}
// 选择解释器
typedef void (*Interpreter)(Thread*);
Interpreter stdInterp;
if (gDvm.executionMode == kExecutionModeInterpFast)
stdInterp = dvmMterpStd;
#if defined(WITH_JIT)
else if (gDvm.executionMode == kExecutionModeJit ||
gDvm.executionMode == kExecutionModeNcgO0 ||
gDvm.executionMode == kExecutionModeNcgO1)
stdInterp = dvmMterpStd;
#endif
else
stdInterp = dvmInterpretPortable;
// Call the interpreter
(*stdInterp)(self);
*pResult = self->interpSave.retval;
/* Restore interpreter state from previous activation */
self->interpSave = interpSaveState;
#if defined(WITH_JIT)
dvmJitCalleeRestore(calleeSave);
#endif
if (savedSubModes != kSubModeNormal) {
dvmEnableSubMode(self, savedSubModes);
}
}
dalvik解释器流程分析
Thread Code技术
while (*ins) {
switch (*ins) {
case NOP:
break;
case MOV:
break;
......
}
}
dvmInterpretPortable源码分析
1. 初始化一些关于虚拟机执行环境的变量
2. 初始化分发表
3. FINISH(0)开始执行指令
void dvmInterpretPortable(Thread* self)
{
DvmDex* methodClassDex; // curMethod->clazz->pDvmDex
JValue retval;
//一些核心的状态
const Method* curMethod; // 要执行的方法
const u2* pc; // 指令计数器
u4* fp; // 函数栈指针
u2 inst; // 当前指令
/* instruction decoding */
u4 ref; // 用来表示类的引用
u2 vsrc1, vsrc2, vdst; // 寄存器索引
/* method call setup */
const Method* methodToCall;
bool methodCallRange;
//建立分发表
DEFINE_GOTO_TABLE(handlerTable);
//初始化上面定义的变量
curMethod = self->interpSave.method;
pc = self->interpSave.pc;
fp = self->interpSave.curFrame;
retval = self->interpSave.retval; /* only need for kInterpEntryReturn? */
methodClassDex = curMethod->clazz->pDvmDex;
if (self->interpBreak.ctl.subMode != 0) {
TRACE_METHOD_ENTER(self, curMethod);
self->debugIsMethodEntry = true; // Always true on startup
}
methodToCall = (const Method*) -1;
//取出第一条指令,并且执行
FINISH(0); /* fetch and execute first instruction */
//下面就是定义了每条指令的处理分支。
//NOP指令的处理程序:什么都不做,然后处理下条指令
HANDLE_OPCODE(OP_NOP)
FINISH(1);
OP_END
.....
invoke-super指令实例分析
#define GOTO_invoke(_target, _methodCallRange) \
do { \
methodCallRange = _methodCallRange; \
goto _target; \
} while(false)
HANDLE_OPCODE(OP_INVOKE_SUPER /*vB, {vD, vE, vF, vG, vA}, meth@CCCC*/)
GOTO_invoke(invokeSuper, false);
OP_END
//invoke-super位描述符如下:A|G|op BBBB F|E|D|C
//methodCallRange depending on whether this is a "/range" instruction.
GOTO_TARGET(invokeSuper, bool methodCallRange)
{
Method* baseMethod;
u2 thisReg;
EXPORT_PC();
//取出AG的值
vsrc1 = INST_AA(inst);
//要调用的method索引
ref = FETCH(1);
//要作为参数的寄存器的索引
vdst = FETCH(2);
//取出this寄存器的索引,比如thisReg为3的话,表示第三个寄存器,放的是this参数。
if (methodCallRange) {
ILOGV("|invoke-super-range args=%d @0x%04x {regs=v%d-v%d}",
vsrc1, ref, vdst, vdst+vsrc1-1);
thisReg = vdst;
} else {
ILOGV("|invoke-super args=%d @0x%04x {regs=0x%04x %x}",
vsrc1 >> 4, ref, vdst, vsrc1 & 0x0f);
thisReg = vdst & 0x0f;
}
//检查this 是否为空
if (!checkForNull((Object*) GET_REGISTER(thisReg)))
GOTO_exceptionThrown();
//解析要调用的方法
baseMethod = dvmDexGetResolvedMethod(methodClassDex, ref);
if (baseMethod == NULL) {
baseMethod = dvmResolveMethod(curMethod->clazz, ref,METHOD_VIRTUAL);
if (baseMethod == NULL) {
ILOGV("+ unknown method or access denied");
GOTO_exceptionThrown();
}
}
if (baseMethod->methodIndex >= curMethod->clazz->super->vtableCount) {
/*
* Method does not exist in the superclass. Could happen if
* superclass gets updated.
*/
dvmThrowNoSuchMethodError(baseMethod->name);
GOTO_exceptionThrown();
}
methodToCall = curMethod->clazz->super->vtable[baseMethod->methodIndex];
#if 0
if (dvmIsAbstractMethod(methodToCall)) {
dvmThrowAbstractMethodError("abstract method not implemented");
GOTO_exceptionThrown();
}
#else
assert(!dvmIsAbstractMethod(methodToCall) ||
methodToCall->nativeFunc != NULL);
#endif
LOGVV("+++ base=%s.%s super-virtual=%s.%s",
baseMethod->clazz->descriptor, baseMethod->name,
methodToCall->clazz->descriptor, methodToCall->name);
assert(methodToCall != NULL);
//调用方法
GOTO_invokeMethod(methodCallRange, methodToCall, vsrc1, vdst);
}
GOTO_TARGET_END
GOTO_TARGET(invokeMethod, bool methodCallRange, const Method* _methodToCall, u2 count, u2 regs)
{
//节选
if (!dvmIsNativeMethod(methodToCall)) {
/*
* "Call" interpreted code. Reposition the PC, update the
* frame pointer and other local state, and continue.
*/
curMethod = methodToCall; //设置要调用的方法
self->interpSave.method = curMethod;
methodClassDex = curMethod->clazz->pDvmDex;
pc = methodToCall->insns; //重置pc到要调用的方法
fp = newFp;
self->interpSave.curFrame = fp;
#ifdef EASY_GDB
debugSaveArea = SAVEAREA_FROM_FP(newFp);
#endif
self->debugIsMethodEntry = true; // profiling, debugging
ILOGD("> pc <-- %s.%s %s", curMethod->clazz->descriptor,
curMethod->name, curMethod->shorty);
DUMP_REGS(curMethod, fp, true); // show input args
FINISH(0); // jump to method start
}
数字壳解释执行前的准备工作
sub_D930
struct GlobalInfo {
DexInfo *dex_info;
vector<MethodInfo*> method_list;
};
struct DexInfo {
void *dexBase; //指向内存中dex的基址
int unknow[12];
void *dexHeader; //指向dex header,用来解析dex的。
.....
optable[];
};
struct MethodInfo {
int dex_type_id; //该方法在dex文件中DexTypeId列表的索引
int dex_class_def_id; // 该方法所在类在dex文件中DexClassDef列表索引
int unknow;
int codeoff; //该方法的DexCode结构距离dex头的偏移。
};
struct StackInfo {
JNIEnv * jni_env;
int registerSize; //函数所需寄存器数量
DexCode *dexCode; //指向DexCode结构
int unkonw;
void *registerSpace; // 放入原始参数, malloc(4 * registerSize)
void *registerSpace2; // 新建一个object引用上面的参数, malloc(4 * registerSize)
int unkonw2;
char key; //解密指令的key
char origin_key; //计算解密指令key所需的一个数据
};
int __fastcall sub_D930(unsigned int a1, JNIEnv *a2, _DWORD *a3)
{
//节选
//获取全局信息
global_info = sub_66BD4(v109, &v114);
if ( v114 & 1 )
j_j_j__ZdlPv(*(v47 + 5));
if ( global_info && (v52 = *(global_info + 4), (*(global_info + 8) - v52) >> 2 > v4) )
{
v53 = v52 + 4 * v4;
a2c = v3;
method_info = *v53;
dexInfo = *global_info;
DexCode = (**global_info + *(*v53 + 12)); // DexCode
((*v3)->PushLocalFrame)();
//创建并初始化StackInfo结构
stackinfo = malloc_1(0x20u); // 创建StackInfo结构
v56 = *DexCode;
*stackinfo = a2c; // stackinfo->jni_env
*(stackinfo + 4) = v56; // stackinfo->registerSize
*(stackinfo + 8) = DexCode; // stackinfo->dexCode
*(stackinfo + 12) = 0;
v57 = 4 * v56;
v58 = malloc_0(4 * v56); // 创建虚拟寄存器栈
*(stackinfo + 16) = v58;
memset(v58, v57, 0);
v59 = malloc_0(v57); // 创建虚拟寄存器栈
*(stackinfo + 20) = v59;
memset(v59, v57, 0);
*(stackinfo + 29) = 0;
*(stackinfo + 28) = 0;
v60 = sub_3E268();
v61 = DexCode;
*(stackinfo + 28) = *DexCode ^ *(v60 + 24) ^ *(method_info + 4) ^ *method_info; // stackinfo->key
*(stackinfo + 29) = *(v60 + 24);
}
int __fastcall sub_D930(unsigned int a1, JNIEnv *a2, _DWORD *a3)
{
//节选
v107 = stackinfo;
proto = (*dexInfo
+ *(*dexInfo
+ *(dexInfo[4] + 60)
+ 4 * *(*dexInfo + *(dexInfo[4] + 76) + 12 * *(*dexInfo + *(dexInfo[4] + 92) + 8 * *(method_info + 4) + 2))));
do
v63 = proto++; // 方法的简单声明: VL
while ( *v63 < 0 );
v64 = j_j_strlen(proto);
v99 = v64;
v65 = *v61 - v61[1]; // 函数内部使用寄存器个数:DexCode.registerSize - DexCode.insSize
v105 = v65 - 1;
v66 = v95 + 1;
v67 = v107;
if ( !*(method_info + 8) )
{
v105 = v65;
v68 = 4 * v65;
v69 = *(*(v107 + 20) + v68); // 函数的第一个参数 thisReg
v96 = *v95;
//节选
v111 = v68;
v73 = (*(v67 + 20) + v68);
v74 = *v73;
if ( *v73 && !*(v74 + 4) )
{
*(v74 + 4) = 1;
v78 = v111;
v77 = v96;
**(*(v67 + 20) + v111) = v96;
}
else
{
v75 = v64;
v76 = malloc_1(8u); // 重新创建了一个MainActivity object,并放入第二个register space位置。
*v76 = 0;
*(v76 + 4) = 0;
v77 = v96;
*v76 = v96;
*(v76 + 4) = 1;
*v73 = v76;
v67 = v107;
v64 = v75;
v78 = v111;
}
*(*(v67 + 16) + v78) = v77; // 直接将Activity实例,放入第一个register space的相应位置、
}
v108 = v67;
if ( v64 >= 2 ) // 处理除了this之外的其他参数。
{
v79 = 1;
v112 = 1;
do
{
v80 = v63[v79++ + 1];
if ( v80 > 89 )
{
if ( v80 == 90 )
{
*(*(v67 + 16) + 4 * (v112++ + v105)) = *v66;
++v66;
}
}
else
{
v81 = v80 - 66;
if ( v81 <= 0x11 )
JUMPOUT(__CS__, *(&off_E308 + v81) + 58120);// 调用jni->newGlobalRef,构造将传递给onCreate的参数
}
}
while ( v79 < v64 );
}
}
sub_3FE5C
struct InterpState {
void *pc;
char key;
DexInfo *dex_info;
};
LOAD:0003FF18 BL malloc_1 ; 创建InterpState结构
LOAD:0003FF1C PUSH {R4}
LOAD:0003FF1E POP {R1}
LOAD:0003FF20 PUSH {R0}
LOAD:0003FF22 POP {R4}
LOAD:0003FF24 STR R4, [SP,#0x74+var_24]
LOAD:0003FF26 LDRB R0, [R1,#0x1C]
LOAD:0003FF28 ADDS R6, #0x10
LOAD:0003FF2A STR R6, [SP,#0x74+var_2C]
LOAD:0003FF2C STR R6, [R4] ; InterpState->pc
LOAD:0003FF2E STRB R0, [R4,#4] ; InterpState->key
LOAD:0003FF30 STR R5, [R4,#8] ; InterpState->dex_info
数字壳解释器模型
//R4寄存器存放的是InterpState结构
LOAD:0003FF5C LDRB R1, [R4,#4] ; 取出key,InterpState->key
LOAD:0003FF5E MOVS R6, #0x31 ; '1'
LOAD:0003FF60 PUSH {R1}
LOAD:0003FF62 POP {R2}
LOAD:0003FF64 ANDS R2, R6
LOAD:0003FF66 LDR R0, loc_402C8
LOAD:0003FF68 PUSH {R0}
LOAD:0003FF6A POP {R3}
LOAD:0003FF6C BICS R3, R1
LOAD:0003FF6E ORRS R3, R2
LOAD:0003FF70 MOVS R2, #0xEF00
LOAD:0003FF74 LSLS R1, R1, #8
LOAD:0003FF76 ANDS R2, R1
LOAD:0003FF78 BICS R0, R1
LOAD:0003FF7A ORRS R0, R2
LOAD:0003FF7C EORS R0, R3
LOAD:0003FF7E LDR R1, [R4] ; 取出pc, Interpstate->pc
LOAD:0003FF80 LDRH R4, [R1] ; 取出指令
//执行完invoke-super后
LOAD:000463EC loc_463EC
LOAD:000463EC
LOAD:000463EC LDR R0, [R4]
LOAD:000463EE ADDS R0, #6
LOAD:000463F0 STR R0, [R4] ; InterpState->pc = InterpState->pc + 6
LOAD:000463F2 BL loc_3FF5C ; 跳转到解释器开头,执行下一条指令。
数字壳invoke-super指令分析
int sub_4878C(int a1, bool methodCallRange, JNIEnv *a3, DexInfo *a4, StackInfo *a5, InterpState *a6, int opNumber, void *a8)
{
//节选
a1a = v8;
dex_base = *v8;
dex_header = *(a1a + 16);
key = *(a6 + 4); // 取出key
v11 = (key << 8) | key;
DexMethodId = dex_base + *(dex_header + 92) + 8 * (*(*a6 + 2) ^ v11);
v13 = dex_base + *(dex_header + 60);
methodName = (dex_base + *(v13 + 4 * *(DexMethodId + 4))); //获取函数名
do
v15 = *methodName++ < 0;
while ( v15 );
DexMethodId2 = (dex_base + *(dex_header + 92) + 8 * (*(*a6 + 2) ^ ((key << 8) | key)));
proto = (dex_base
+ *(v13
+ 4 * *(dex_base + *(dex_header + 68) + 4 * *(dex_base + *(dex_header + 76) + 12 * *(DexMethodId + 2) + 4))));
do
v17 = *proto++; //获取函数简单声明
while ( v17 < 0 );
v18 = *(*a6 + 4);
if ( v52 == 1 )
thisReg = v18 ^ ((key << 8) | key); //this参数
else
thisReg = (v18 ^ key) & 0xF;
v20 = 0;
if ( v51 )
{
v21 = *(*(a5 + 20) + 4 * thisReg);
if ( !v21 || (v20 = *v21) == 0 )
{
v30 = ((*v53)->FindClass)(v53, "java/lang/NullPointerException");
.....
}
}
arg0 = v20; // this object
v62 = v53;
v63 = 0;
if ( ((*v53)->ExceptionCheck)(v53) )
v63 = 0;
if ( v51 != 2 && v51 != 4 )
{
sub_610BC(a1a, v53, *DexMethodId2); // 获取到classid所指定的类
return sub_48AE2(v32, v33, v34, v35, a5); // 利用jni->CallVoidMethod调用父类方法
}
//48EAA: 构建invoke-super除this外的参数
//49770:调用jni->CallVoidMethod方法
看雪ID:glider菜鸟
https://bbs.pediy.com/user-657393.htm
推荐文章++++
* CVE-2017-13258 Android 蓝牙BNEP漏洞分析