由于在加壳时插入了System.loadLibrary("advmp");,看一下JNI_OnLoad
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) {
return JNI_ERR;
}
// 注册本地方法。
registerFunctions(env);
// 获得apk路径。
gAdvmp.apkPath = GetAppPath(env);
MY_LOG_INFO("apk path:%s", gAdvmp.apkPath);
// 释放yc文件。
gAdvmp.ycSize = ReleaseYcFile(gAdvmp.apkPath, &gAdvmp.ycData);
if (0 == gAdvmp.ycSize) {
MY_LOG_WARNING("release Yc file fail!");
goto _ret;
}
// 解析yc文件。
gAdvmp.ycFile = new YcFile;
if (!gAdvmp.ycFile->parse(gAdvmp.ycData, gAdvmp.ycSize)) {
MY_LOG_WARNING("parse Yc file fail.");
goto _ret;
}
_ret:
return JNI_VERSION_1_4;
}
在这里解析了yc文件,并保存在了内存中(gAdvmp.ycFile)
看一下MainActivity
public class MainActivity extends Activity {
public static final String TAG = "debug";
private Button mbtnTest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nativeLog();
mbtnTest = (Button) findViewById(R.id.btnTest);
mbtnTest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int result = separatorTest(2);
Log.i(TAG, "separatorTest result:" + result);
}
});
}
private native int separatorTest(int value);
private native static void nativeLog();
static {
System.loadLibrary("advmp");
}
}
壳已经将separatorTest 转化为了native方法了
当执行时就会执行到相应的native方法(也是之前壳生成的cpp代码)
jint separatorTest(JNIEnv* env, jobject thiz, jint value) {
MY_LOG_INFO("separatorTest - value=%d", value);
jvalue result = BWdvmInterpretPortable(gAdvmp.ycFile->GetSeparatorData(0), env, thiz, value);
return result.i;
}
关键就是BWdvmInterpretPortable
,这个函数实现的转发,看一下它的实现, 它在InterpC.cpp,这是一个自定义指令解释器的实现
InterpC.cpp::BWdvmInterpretPortable
jvalue BWdvmInterpretPortable(const SeparatorData* separatorData, JNIEnv* env, jobject thiz, ...) {
jvalue* params = NULL; // 参数数组。
jvalue retval; // 返回值。
const u2* pc; // 程序计数器。
u4 fp[65535]; // 寄存器数组。
u2 inst; // 当前指令。
u2 vsrc1, vsrc2, vdst; // usually used for register indexes
unsigned int startIndex;
// 处理参数。
va_list args;
va_start(args, thiz);
params = getParams(separatorData, args);
va_end(args);
// 获得参数寄存器个数。
size_t paramRegCount = getParamRegCount(separatorData);
// 设置参数寄存器的值。
if (isStaticMethod(separatorData)) {
startIndex = separatorData->registerSize - separatorData->paramSize;
} else {
startIndex = separatorData->registerSize - separatorData->paramSize;
fp[startIndex++] = (u4)thiz;
}
for (int i = startIndex, j = 0; j < separatorData->paramSize; j++ ) {
if ('D' == separatorData->paramShortDesc.str[i] || 'J' == separatorData->paramShortDesc.str[i]) {
fp[i++] = params[j].j & 0xFFFFFFFF;
fp[i++] = (params[j].j >> 32) & 0xFFFFFFFF;
} else {
fp[i++] = params[j].i;
}
}
pc = separatorData->insts;
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
// 抓取第一条指令。
FINISH(0);
/*--- start of opcodes ---*/
/* File: c/OP_NOP.cpp */
HANDLE_OPCODE(OP_NOP)
FINISH(1);
OP_END
这里通过数组来模拟寄存器, 通过int指针来模拟pc寄存器,完成各个指令的运算,比如
HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
vdst = INST_A(inst);
vsrc1 = INST_B(inst);
MY_LOG_VERBOSE("|move%s v%d,v%d %s(v%d=0x%08x)",
(INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
kSpacing, vdst, GET_REGISTER(vsrc1));
SET_REGISTER(vdst, GET_REGISTER(vsrc1));
FINISH(1);
OP_END
HANDLE_OPCODE(OP_MOVE /*vA, vB*/)
,生成的是一个goto用的标签,
在FINISH中会有一个goto来实现跳转
# define FINISH(_offset) { \
ADJUST_PC(_offset); \
inst = FETCH(0); \
/*if (self->interpBreak.ctl.subMode) {*/ \
/*dvmCheckBefore(pc, fp, self);*/ \
/*}*/ \
goto *handlerTable[INST_INST(inst)]; \
}
通过这种方式来完成多行指令的顺序执行
知道遇到RETURN
指令结束执行,返回返回值
HANDLE_OPCODE(OP_RETURN /*vAA*/)
vsrc1 = INST_AA(inst);
MY_LOG_VERBOSE("|return%s v%d",
(INST_INST(inst) == OP_RETURN) ? "" : "-object", vsrc1);
retval.i = GET_REGISTER(vsrc1);
/*GOTO_returnFromMethod();*/
GOTO_bail();
OP_END
.....
bail:
if (NULL != params) {
delete[] params;
}
MY_LOG_INFO("|-- Leaving interpreter loop");
return retval;
执行原理结论:
- JNI_OnLoad 读取yc文件,获取指令
- native 中执行BWdvmInterpretPortable 主要入参为从yc中获得的separatorData
- 通过自定义解释器逐行指令指令,并返回返回值
ps: 这个开源项目提供的是一种思路,不可用于商用, 仅支持计算用指令的解释, 引用类的指令解释未实现
标签:vsrc1,inst,separatorData,gAdvmp,INST,加固,ADVMP,vmp,OP From: https://www.cnblogs.com/gradyblog/p/17317993.html