如何编写一个so文件:教我兄弟学android逆向06
windows环境下,NDK编译需要添加的include头文件(根据编译的版本需要进行修改):
右击项目 --> Properties --> 左侧C/C++ General --> Paths and Symbols --> 右侧Includes --> GNU C++(.cpp) --> Add
${NDKROOT}\platforms\android-19\arch-arm\usr\include
${NDKROOT}\sources\cxx-stl\gnu-libstdc++\4.8\include
${NDKROOT}\sources\cxx-stl\gnu-libstdc++\4.8\libs\armeabi\include
${NDKROOT}\toolchains\arm-Linux-androideabi-4.8\prebuilt\windows\lib\gcc\arm-linux-androideabi\4.8\include
具体配置: https://github.com/boyliang/ndk-patch (将下载的文件解压后复制到自己所需要ndk的androdi版本目录下)
在java中调用so库的代码:
//这里是静态加载,在生成so文件时,系统添加了lib前缀和.so后缀,这里参数就没有前缀和后缀
static{
System.loadLibrary("mylib");
}
在smali语法中调用so库的代码是
const-string v0, "mylib"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
ps:在一个成品软件逆向过程中插入so时,需要将编译好的so文件复制到apk的lib目录下。
因为android 调用so的时候用的时system.loadLibrary,所以要从这里的下手,下面是流程
作者源代码
phdr_num_ = header_.e_phnum;
// Like the kernel, we only accept prograa header tables that
// are smaller than 64KiB.
if (phdr_num_ < 1 | | phdr_num_ > 65536/sizeof (Elf32_Phdr)) {
DL.ERR("\"%s\" has invalid e_phnum:%d", name_, phdr_num_);
return false;
}
Elf32_Addr page_min = PAGE_START (header_.e_phoff);
Elf32_Addr page_max = PAGE_END (header_.e_phoff + (phdr_num_ * sizeof (Elf32_Phdr)));
Elf32_Addr page_offset = PAGE_OFFSET (header_.e_phoff);
phdr_size_ = page_max - page_min;
void* mmap_result =mmap(NULL, phdr_size_, PROT_READ, MAP_PRIVATE,fd_, page_min)
if (mmap_result = MAP_FAILED) {
DL-ERR("\"%s\" phdr mmap failed: %s", strerror(error));
return false;
}
PROT.READ, HAP.PRIVATE, fd_, pagejitm);
phdr_mmap_ = mmap_result;
phdr_table_ = reinterpret_cast(reinterpret_cast(mmap_result) + phdr_offset);
return true;
Elf32_Addr min_vaddr;
load_size_ = phdr_table_get_load_size(phdr_table_, phdr_num_, &min_vaddr);
if (load_size_ = 0) {
DL_ERR("\"%s\" has no loadable segments", name_) ;
return false:
}
uint8_t* addr = reinterpret_cast (min_vaddr);
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
void* start = mmap (addr, load_size_, PR0T_N0NE, mmap_flags, -1, 0) ;
if (start == MAP_FAILED) {
DL_ERR(" couldn’t reserve %d bytes of address space for \"%s\"", load_size_,)
return false:
}
load_start_ = start;
load_bias_ = reinterpret_cast (start) - addr;
return true;
// reserve the address space range for the library.
// TODO: assert assumption.
bool ELfReader: :LoadSegnents() {
for (size_t i = 0: i < phdr_num_: ++i) {
const Elf32_Phdr* phdr = &phdr_table_[i];
if (phdr->p_type != PT_LOAD) {
continue;
}
}
// Segment addresses in memory.
Elf32_Addr seg_start = phdr->p_vaddr + load_bias_;
Elf32_Addr seg_end = seg_start + phdr->p_memsz;
Elf32_Addr seg_page_start = PAGE_START (seg_start);
Elf32_Addr seg_page_end = PAGEJBND (seg_end) ;
Elf32_Addr seg_file_end = seg_start + phdr->p_filesz;
// File offsets.
Elf32_Addr file_start - phdr~>p_offset;
Elf32_Addr file_end - file_start + phdr->p_filesz;
Elf32_Addr filejpage.start = PAGE.START (file.start):
Elf32_Addr file_length = file_end • file_page_start;
if (file_length != 0) {
void* seg_addr = mmap ((void*4)seg page start,fileJLength,
PFLAGS_TO_PSOT(phdr->p_flags),HAP_FIXED|MAP_PRIVATE,fd_,
file_page_start);
static bool soinfo_link_image(soinfo* si) {
/* "base" might wrap around UINT32_MAX.*/
Elf32_Addr base = si->load_bias;
const Elf32 Phdr *phdr = si->phdr;
int phnum = si->phnum;
bool relocating_linker = (si->fLags & FLAG_LINKER) ! = 0;
/* We can t debug anything until the linker is relocated */
if (! relocating_linker) {
IHF0("[ linking %s ]", si->name);
DEBUG ("si->base = 0x%08x si->flags = 0x%08x", si~>base, si->flags);
}
/*Extract dynamic section */
size_t dynamc_count;
Elf32_Word dynamic_flags;
phdr_table_get_dynami c_secti on (phdr, phntun, base, &si->dynamic,
Adynajnic_cormt, &dynamic_£Lags) ;
if (si->dynamic == HULL) {
if Grelocating linker) {
DL.ERR ("missing PT.DYNAMIC in \"%s\"", si->name);
}
return false;
}
soinfo** needed = (soinfo**) alloca((l + needed_count) * sizeof (soinfo*));
soinfo** pneeded = needed;
for (Elf32_Dyn* d = si->dynamic; d->d_tag != DT_NULL; ++d) {
if (d->d_tag == DT.NEEDED) {
const char* library_name = si->strtab + d->d_un.d_val;
DEBUG("%s needs %s", si->name, library_name) ;
soinfo* lsi = find_library(library_name);
if(lsi == HULL) {
strlcpy (tmp_err_buf, linker_get_error_buffer(),sizeof(tmp_err_buf));
DL_ERR ("could not load library \"%s\" needed by \"%s\*; caused by %s",
library_name, si->name, tmp_err_buf):
return false;
}
*pneeded++ = lsi;
}
void soinfo: :CallArray(const char* array_name UNUSED, linker_function_t* functions, size_t count, bool reverse) {
if (functions == NULL) {
return;
}
TRACE ("[ Celling %s (size %d) @ ftp for ' %s' ]", array_name, count, functions, name);
int begin = reverse ? (count - 1) : 0;
int end = reverse ? -1 : count;
int step = reverse ? -1 : 1;
for (int i = begin; i != end; i += step) {
TRACE ("[ %s[ftd] == ftp ]", array_name, i, functions [i]):
CallFunction(" function", functions[i]) ;
}
TRACE ("[ Done celling %s for ' %s' ]", array_name, name) ;
}
void soinfo: :CellFunction(const char* function_name UNUSED, linker_function_t function) {
if (function == NULL || reinterpret_cast(function) == static_cast(-l)) {
return;
}
TRACE ("[ Celling %s Q ftp for ' %s' ]", function_name, function, name);
function();
TRACE ("[ Done celling %s 6 ftp for ' %s' ]", function_name, function, name);
// The function may have celled dlopen(3) or diclose (3), so we need to ensure our date structures
// ere still writable.This happens with our debug malloc (see http://b/7941716)
set_soinfo_pool_protection(PROT_READ | PR0T_WRITE);
}
set_soinfo_jpool_protection (PR0T_READ | PROT_WRITE);
const char target_fun[] = "JNI_0nload";
funclnfo info;
int i;
// unsigned int npage, base * getLibAddr();
unsigned int npage, base=baseParam;
__android_log_print(ANDROID_LOG_INFO, "liumeng", "base addr * 0x%x", base);
if(getTargetFuncInfo(base, target_fun, &info) == -1){
print_debug(MFind 3NI_OnLoad failed*');
return ;
}
npage = info.st.size / PAGE_SIZE + ((info.st_size % PAGE.SIZE == 0) ? 0 : 1);
if(mprotect((void *) ((base + info.st.value) / PAGE.SIZE * PAGE.SIZE), npage, PROT_READ | PROT.EXEC | PROT_VJRITE
print_debug('*mem privilege change failed");
}
for(i=0;i< info.st_size - 1; i++){
char *addr = (char*)(base + info.st_value -1 + i);
*addr = ~(*addr);
}
if(mprotect((void *) ((base + info.st.value) / PAGE.SIZE * PAGE_SIZE), npage, PROT.READ | PROT.EXEC) ! = 0){
print_debug("mem privilege change failed");
}
print_debug("mem success”);