//第一种
unsigned char spAdd8[4];
numberToByteArray(SP+8,spAdd8,4);
printBytes(spAdd8,4);
// uc_mem_write(uc,base+0x26BBC, spAdd8,4);
uc_mem_write(uc,base+0x26BBC,"\x08\xfc\xef\x40",4);
uc_mem_write(uc,SP+8,"\x00\x00\x00\x00",4);
printf("fdsfds\n");
unsigned char spAdd8[4];
uint64_t ox=0x50000000;
uc_mem_map(uc,ox,0x1000,UC_PROT_ALL);//分配内存最小值0x1000
numberToByteArray(ox,spAdd8,4);
printBytes(spAdd8,4);
uc_mem_write(uc,base+0x26BBC, spAdd8,4);
uc_mem_write(uc,ox,"\x00",1);
printf("fdsfds\n");
注意经测试uc_mem_map分配size小于0x1000,会导致报错。另外在arm指令中,如ldr r0,[r0]中,其读取的内存区间一定要在分配的内存中,不然会报unmap的错。
//第一种
unsigned char spAdd8[4];
numberToByteArray(SP+8,spAdd8,4);
printBytes(spAdd8,4);
// uc_mem_write(uc,base+0x26BBC, spAdd8,4);
uc_mem_write(uc,base+0x26BBC,"\x08\xfc\xef\x40",4);
uc_mem_write(uc,SP+8,"\x00\x00\x00\x00",4);
printf("fdsfds\n");
unsigned char spAdd8[4];
uint64_t ox=0x50000000;
uc_mem_map(uc,ox,0x1000,UC_PROT_ALL);//分配内存最小值0x1000
numberToByteArray(ox,spAdd8,4);
printBytes(spAdd8,4);
uc_mem_write(uc,base+0x26BBC, spAdd8,4);
uc_mem_write(uc,ox,"\x00",1);
printf("fdsfds\n");
以下是最为重要的一种。必须牢牢掌握。
//第三种:
uint32_t re=0;
uint32_t* ptrRe=&re;//把64位的指针转换成32位的
printf("ptrRe:0x%x\n", ptrRe);
uintptr_t address= reinterpret_cast<uintptr_t>(ptrRe);//把指针转成数字
printf("address,%x\n",address);
printf("address2,%x\n",address&0xfffff000);//后三数清0
unsigned char bytearr[4];
numberToByteArray(address,bytearr,4);
uc_mem_map(uc, address&0xfffff000, 0x10000, UC_PROT_ALL);//base的最后三位也要为0,arm中只能是4个字节,多于4个字节会超过寻址能力,分配内存最小值0x1000
uc_mem_write(uc,base+0x26BBC, bytearr,4);//这里就能二级指针映射到re的值0呢
注意经测试uc_mem_map分配size小于0x1000,会导致报错。另外在arm指令中,如ldr r0,[r0]中,其读取的内存区间一定要在分配的内存中,不然会报unmap的错。
以下为整个页面源代码:
//test.cpp
// Created by cxl on 10/8/23.
//
//
// Created by cxl on 2023-10-05.
//
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <iomanip>
#include "unicorn/unicorn.h"
#include "capstone/capstone.h"
#include "utils.h"
static csh handle;
using namespace std;
long getfilelength(FILE *fp)
{
long curpos=0L;
long length=0L;
curpos = ftell(fp);
fseek(fp, 0L, SEEK_END);
length = ftell(fp);
fseek(fp, curpos, SEEK_SET);
return length;
}
string trans(string s){
std::ifstream file(s, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return "fail";
}
std::stringstream ss;
ss << std::hex << std::uppercase << std::setfill('0');
char c;
while (file.get(c)) {
ss << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(c));
}
std::string hexString = ss.str();
std::cout << hexString << std::endl;
return hexString;
}
void hook_code(uc_engine *uc, uint64_t address, uint32_t size,void *user_data){
cs_insn *insn;
unsigned char* code=new unsigned char[size];
uc_mem_read(uc,address,code,size);
//printBytes(code,size);
size_t count=cs_disasm(handle,code,size,0,0,&insn);
if(address==0x400115ec){
int re;
uc_reg_read(uc,UC_ARM_REG_R0,&re);
printf("0x400115ec,r0 result Is %x\n",re);
}
if(address==0x400115ee){
printf("enter...\n");
int re;
uc_reg_read(uc,UC_ARM_REG_R0,&re);
printf("0x400115ee,r0 result Is %x\n",re);
}
if(address==0x4001160a){
printf("enter...\n");
int re;
uc_reg_read(uc,UC_ARM_REG_R0,&re);
printf("0x4001160a,r0 result Is %d\n",re);
}
if(count){
for (int i = 0; i < count; ++i) {
printf("count %d 0x%" PRIx64 ":\t%s\t%s\n", count,address, insn[i].mnemonic, insn[i].op_str);
}
}else{
printf("count value is 0");
}
}
int main(){
try{
uint64_t start_addr=0x115E0;
uint64_t end_addr=0x1160C;
uint64_t base=0x40000000;
uint64_t base_offset=0x00F00000;//10M
uint64_t r0=1;
uint64_t r1=2;
uint64_t SP=base+base_offset-0x400;
uint64_t lR=base+0x234;
uc_hook trace;
uc_engine* uc;
uc_err err=uc_open(UC_ARCH_ARM,UC_MODE_THUMB,&uc);
cs_err csErr=cs_open(CS_ARCH_ARM,CS_MODE_THUMB,&handle);
if (err != UC_ERR_OK) {
printf("Failed on uc_mem_map() with error returned: %u\n", err);
}
if (csErr) {
printf("Failed on cs_open() with error returned: %u\n", err);
abort();
}
size_t fileSize=0;
unsigned char* bytearray=readFileToByteArray("../bin/libnative-lib.so",fileSize);
// cout<<setw(2)<<hex<<uppercase<<setfill('0')<<static_cast<int>(bytearray[fileSize-8])<<endl;
//printBytes(bytearray, fileSize);
cs_insn *insn;
//unsigned char block[]={0x80,0xb5,0x6F,0x46};
unsigned char* block=arraySlice(bytearray,start_addr,end_addr);
size_t count=cs_disasm(handle,block,end_addr-start_addr,0,20,&insn);
// size_t count=cs_disasm(handle,(unsigned char *)THUMB_CODE,sizeof(THUMB_CODE) - 1,0x80001000,0,&insn);
cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
if(count){
for (int i = 0; i < count; ++i) {
printf("0x%" PRIx64 ":\t%s\t%s\n", insn[i].address, insn[i].mnemonic, insn[i].op_str);
// print_insn_detail(handle,&insn[i]);
}
}else{
printf("ERROR: Failed to disasm given code!\n");
}
printf("capstone end.....\n");
uc_mem_map(uc,base,base_offset,UC_PROT_ALL);
uc_mem_write(uc,base,bytearray,fileSize);
//string s=trans("../bin/libnative-lib.so");
//uc_mem_write(uc,base,s.c_str(),s.length());
uc_reg_write(uc,UC_ARM_REG_R0, &r0);
uc_reg_write(uc,UC_ARM_REG_R1,&r1);
uc_reg_write(uc,UC_ARM_REG_SP,&SP);
uc_reg_write(uc,UC_ARM_REG_LR,&lR);
uint32_t re=0;
uint32_t* ptrRe=&re;//把64位的指针转换成32位的
printf("ptrRe:0x%x\n", ptrRe);
uintptr_t address= reinterpret_cast<uintptr_t>(ptrRe);//把指针转成数字
printf("address,%x\n",address);
printf("address2,%x\n",address&0xfffff000);//后三数清0
unsigned char bytearr[4];
numberToByteArray(address,bytearr,4);
uc_mem_map(uc, address&0xfffff000, 0x10000, UC_PROT_ALL);//base的最后三位也要为0,arm中只能是4个字节,多于4个字节会超过寻址能力,分配内存最小值0x1000
uc_mem_write(uc,base+0x26BBC, bytearr,4);//这里就能二级指针映射到re的值0呢
//uc_mem_write(uc,address,"\x00",1);
uc_hook_add(uc, &trace, UC_HOOK_CODE, reinterpret_cast<void*>(hook_code), NULL, 1, 0);
uc_emu_start(uc,base+start_addr+1,base+end_addr,0,0);
uint64_t r0_result;
uc_reg_read(uc,UC_ARM_REG_R0,&r0_result);
printf("r0 xxis: %d\n",r0_result);//输出3,结果正确。
delete[] bytearray;
} catch (exception variable) {
cout<<"err"<<endl;
}
}
注意经测试uc_mem_map分配size小于0x1000,会导致报错。另外在arm指令中,如ldr r0,[r0]中,其读取的内存区间一定要在分配的内存中,不然会报unmap的错。