12 Commits

Author SHA1 Message Date
jiqiu2021
933b962d6e fix errlog 2024-11-16 23:04:25 +08:00
jiqiu2021
8b489d0c5c fix 正常应用隐藏失败,增加LOG日志方便排查,已经正式机型测试成功 2024-11-16 23:00:12 +08:00
jiqiu2021
8e715b8148 fix 隐藏失败的问题,并且处理了原来riru内存泄漏的问题 2024-11-16 21:56:05 +08:00
jiqiu2021
b50d500319 补全文件 2024-11-15 15:33:18 +08:00
jiqiu2021
a50ca00c54 修改隐藏so名称 2024-11-15 15:31:05 +08:00
jiqiu2021
79cb1e47b3 修改隐藏so名称 2024-11-15 15:29:26 +08:00
jiqiu2021
074e03ca15 增加riru注入隐藏,手上没手机,没法注入,有问题再修吧 2024-11-15 15:27:04 +08:00
Ji qiu
cca6a126ac Merge pull request #2 from jiqiu2022/update-readme
Update readme
2024-11-15 14:24:13 +08:00
jiqiu2021
14ad58ec74 添加readme 2024-11-15 14:22:19 +08:00
jiqiu2021
7d5a626750 恢复规范,增加一定注释 2024-11-15 14:10:13 +08:00
jiqiu2021
be5208409d jni调用 2024-10-28 22:20:58 +08:00
jiqiu2021
fd5799cc95 多模块注入 2024-10-13 15:33:53 +08:00
11 changed files with 652 additions and 59 deletions

View File

@@ -1,21 +1,48 @@
# Zygisk-Il2CppDumper
Il2CppDumper with Zygisk, dump il2cpp data at runtime, can bypass protection, encryption and obfuscation.
# [Zygisk-MyInjector](https://github.com/jiqiu2022/Zygisk-MyInjector)
中文说明请戳[这里](README.zh-CN.md)
## How to use
1. Install [Magisk](https://github.com/topjohnwu/Magisk) v24 or later and enable Zygisk
2. Build module
原项目https://github.com/Perfare/Zygisk-Il2CppDumper
本项目在原项目基础上做局部更改,请支持原项目作者劳动成果
1. 安装[Magisk](https://github.com/topjohnwu/Magisk) v24以上版本并开启Zygisk
2. 生成模块
- GitHub Actions
1. Fork this repo
2. Go to the **Actions** tab in your forked repo
3. In the left sidebar, click the **Build** workflow.
4. Above the list of workflow runs, select **Run workflow**
5. Input the game package name and click **Run workflow**
6. Wait for the action to complete and download the artifact
1. Fork这个项目
2. 在你fork的项目中选择**Actions**选项卡
3. 在左边的侧边栏中,单击**Build**
4. 选择**Run workflow**
5. 输入游戏包名并点击**Run workflow**
6. 等待操作完成并下载
- Android Studio
1. Download the source code
2. Edit `game.h`, modify `AimPackageName` to the game package name
3. Use Android Studio to run the gradle task `:module:assembleRelease` to compile, the zip package will be generated in the `out` folder
3. Install module in Magisk
4. Start the game, `dump.cs` will be generated in the `/data/data/AimPackageName/files/` directory
1. 下载源码
2. 编辑`game.h`, 修改`GamePackageName`为游戏包名
3. 使用Android Studio运行gradle任务`:module:assembleRelease`编译zip包会生成在`out`文件夹下
3. Magisk里安装模块
4. 将要注入的so放入到/data/local/tmp下修改为test.so
(部分手机第一次注入不会成功,请重启,再之后的注入会成功)
目前正在开发的分支:
1. 使用Java的System.load加载so
2. 注入多个so的分支
计划开发:
1. 第一步仿照Riru将注入的so进行内存上的初步隐藏可以对抗部分业务检测游戏安全相关已经补齐建议不要尝试
2. 第二步实现一个自定义的linker进行更深层次的注入隐藏
3. 第三步,搭配对应配套手机的内核模块对注入的模块进行进一步完美擦除,达到完美注入的目的
以此项目为脚手架的计划开发:
1. 一个全新的Frida框架保留大部分原生api并可以过任何相关注入检测
2. 一个全新的Trace框架高性能Trace速度是Stallker的60倍并且支持更全面的信息打印。具体效果可以参考看雪帖子
3. 一个全新的无痕调试框架支持像GDB一样调试没有ptrace痕迹两种思路进行无痕调试基于硬件断点以及基于VM

View File

@@ -1,19 +0,0 @@
# Zygisk-Il2CppDumper
Zygisk版Il2CppDumper在游戏运行时dump il2cpp数据可以绕过保护加密以及混淆。
## 如何食用
1. 安装[Magisk](https://github.com/topjohnwu/Magisk) v24以上版本并开启Zygisk
2. 生成模块
- GitHub Actions
1. Fork这个项目
2. 在你fork的项目中选择**Actions**选项卡
3. 在左边的侧边栏中,单击**Build**
4. 选择**Run workflow**
5. 输入游戏包名并点击**Run workflow**
6. 等待操作完成并下载
- Android Studio
1. 下载源码
2. 编辑`game.h`, 修改`AimPackageName`为游戏包名
3. 使用Android Studio运行gradle任务`:module:assembleRelease`编译zip包会生成在`out`文件夹下
3. 在Magisk里安装模块
4. 启动游戏,会在`/data/data/AimPackageName/files/`目录下生成`dump.cs`

View File

@@ -36,6 +36,8 @@ aux_source_directory(xdl xdl-src)
add_library(${MODULE_NAME} SHARED
main.cpp
hack.cpp
newriruhide.cpp
pmparser.cpp
${xdl-src})
target_link_libraries(${MODULE_NAME} log)

View File

@@ -5,6 +5,6 @@
#ifndef ZYGISK_IL2CPPDUMPER_GAME_H
#define ZYGISK_IL2CPPDUMPER_GAME_H
#define AimPackageName "com.example.testdlopen"
#define AimPackageName "com.tencent.mobileqq"
#endif //ZYGISK_IL2CPPDUMPER_GAME_H

View File

@@ -18,28 +18,34 @@
#include <sys/stat.h>
//#include <asm-generic/fcntl.h>
#include <fcntl.h>
void hack_start(const char *game_data_dir,JavaVM *vm) {
#include "newriruhide.h"
void load_so(const char *game_data_dir, JavaVM *vm, const char *soname) {
bool load = false;
LOGI("hack_start %s", game_data_dir);
// 构建新文件路径
char new_so_path[256];
snprintf(new_so_path, sizeof(new_so_path), "%s/files/%s.so", game_data_dir, "test");
// 复制 /sdcard/test.so 到 game_data_dir 并重命名
const char *src_path = "/data/local/tmp/test.so";
// 构建新文件路径,使用传入的 soname 参数
char new_so_path[256];
snprintf(new_so_path, sizeof(new_so_path), "%s/files/%s.so", game_data_dir, soname);
// 构建源文件路径
char src_path[256];
snprintf(src_path, sizeof(src_path), "/data/local/tmp/%s.so", soname);
// 打开源文件
int src_fd = open(src_path, O_RDONLY);
if (src_fd < 0) {
LOGE("Failed to open %s: %s (errno: %d)", src_path, strerror(errno), errno);
return;
}
// 打开目标文件
int dest_fd = open(new_so_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (dest_fd < 0) {
LOGE("Failed to open %s", new_so_path);
close(src_fd);
return;
}
// 复制文件内容
char buffer[4096];
ssize_t bytes;
@@ -52,40 +58,54 @@ void hack_start(const char *game_data_dir,JavaVM *vm) {
}
}
// 关闭文件描述符
close(src_fd);
close(dest_fd);
// 修改文件权限
if (chmod(new_so_path, 0755) != 0) {
LOGE("Failed to change permissions on %s: %s (errno: %d)", new_so_path, strerror(errno), errno);
return;
} else {
LOGI("Successfully changed permissions to 755 on %s", new_so_path);
}
// 加载 .so 文件
void *handle;
// 使用 xdl_open 打开新复制的 so 文件
for (int i = 0; i < 10; i++) {
// void *handle = xdl_open(new_so_path, 0);
handle = dlopen(new_so_path, RTLD_NOW | RTLD_LOCAL);
if (handle) {
LOGI("Successfully loaded %s", new_so_path);
load = true;
char new_soname[256];
sprintf(new_soname, "%s.so", soname);
riru_hide(new_soname);
break;
} else {
LOGE("Failed to load %s: %s", new_so_path, dlerror());
sleep(1);
}
}
// 如果加载失败
if (!load) {
LOGI("test.so not found in thread %d", gettid());
}
void (*JNI_OnLoad)(JavaVM *, void *);
*(void **) (&JNI_OnLoad) = dlsym(handle, "JNI_OnLoad");
if (JNI_OnLoad) {
LOGI("JNI_OnLoad symbol found, calling JNI_OnLoad.");
JNI_OnLoad(vm, NULL);
} else {
LOGE("JNI_OnLoad symbol not found in %s", new_so_path);
LOGI("%s.so not found in thread %d", soname, gettid());
}
// 查找 JNI_OnLoad 并调用
// void (*setupSignalHandler)();
// *(void **) (&setupSignalHandler) = dlsym(handle, "setupSignalHandler");
//
// if (setupSignalHandler) {
// LOGI("setupSignalHandler symbol found, calling setupSignalHandler.");
// setupSignalHandler(); // 调用找到的函数
// } else {
// LOGE("setupSignalHandler symbol not found in %s", new_so_path);
// }
}
void hack_start(const char *game_data_dir,JavaVM *vm) {
load_so(game_data_dir,vm,"test");
//如果要注入多个so那么就在这里不断的添加load_so函数即可
}
std::string GetLibDir(JavaVM *vms) {

View File

@@ -7,10 +7,10 @@
#include <android/log.h>
#define LOG_TAG "Perfare"
#define LOG_TAG "myinjector"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno))
#endif //ZYGISK_IL2CPPDUMPER_LOG_H

View File

@@ -25,7 +25,11 @@ public:
void preAppSpecialize(AppSpecializeArgs *args) override {
auto package_name = env->GetStringUTFChars(args->nice_name, nullptr);
auto app_data_dir = env->GetStringUTFChars(args->app_data_dir, nullptr);
LOGI("preAppSpecialize %s %s", package_name, app_data_dir);
// if (strcmp(package_name, AimPackageName) == 0){
// args->runtime_flags=8451;
// }
LOGI("preAppSpecialize %s %s %d", package_name, app_data_dir,args->runtime_flags);
preSpecialize(package_name, app_data_dir);
env->ReleaseStringUTFChars(args->nice_name, package_name);
env->ReleaseStringUTFChars(args->app_data_dir, app_data_dir);

View File

@@ -0,0 +1,134 @@
//
// Created by Mac on 2024/11/15.
//
// 给riru修复了内存泄漏的问题
#include "newriruhide.h"
/**
* Magic to hide from /proc/###/maps, the idea is from Haruue Icymoon (https://github.com/haruue)
*/
extern "C" {
int riru_hide(const char *name) ;
}
#ifdef __LP64__
#define LIB_PATH "/system/lib64/"
#else
#define LIB_PATH "/system/lib/"
#endif
struct hide_struct {
procmaps_struct *original;
uintptr_t backup_address;
};
static int get_prot(const procmaps_struct *procstruct) {
int prot = 0;
if (procstruct->is_r) {
prot |= PROT_READ;
}
if (procstruct->is_w) {
prot |= PROT_WRITE;
}
if (procstruct->is_x) {
prot |= PROT_EXEC;
}
return prot;
}
#define FAILURE_RETURN(exp, failure_value) ({ \
__typeof__(exp) _rc; \
_rc = (exp); \
if (_rc == failure_value) { \
PLOGE(#exp); \
return 1; \
} \
_rc; })
static int do_hide(hide_struct *data) {
auto procstruct = data->original;
auto start = (uintptr_t) procstruct->addr_start;
auto end = (uintptr_t) procstruct->addr_end;
auto length = end - start;
int prot = get_prot(procstruct);
// backup
data->backup_address = (uintptr_t) FAILURE_RETURN(
mmap(nullptr, length, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0),
MAP_FAILED);
LOGD("%" PRIxPTR"-%" PRIxPTR" %s %ld %s is backup to %" PRIxPTR, start, end, procstruct->perm,
procstruct->offset,
procstruct->pathname, data->backup_address);
if (procstruct->is_r || procstruct->is_x) { // If readable or executable
LOGD("memcpy -> backup");
memcpy((void *) data->backup_address, (void *) start, length);
// Unmap original memory region
LOGD("munmap original");
FAILURE_RETURN(munmap((void *) start, length), -1);
// Remap backup memory to original location
LOGD("mmap original with backup");
FAILURE_RETURN(mmap((void *) start, length, prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0),
MAP_FAILED);
}
return 0;
}
int riru_hide(const char *name) {
procmaps_iterator *maps = pmparser_parse(-1);
if (maps == nullptr) {
LOGE("cannot parse the memory map");
return false;
}
char buf[PATH_MAX];
hide_struct *data = nullptr;
size_t data_count = 0;
procmaps_struct *maps_tmp;
while ((maps_tmp = pmparser_next(maps)) != nullptr) {
bool matched = false;
#ifdef DEBUG_APP
matched = strstr(maps_tmp->pathname, "libriru.so");
#endif
matched = strstr(maps_tmp->pathname, name) != nullptr;
// Match the memory regions we want to hide
if (!matched) continue;
LOGI("matched %s", maps_tmp->pathname);
auto start = (uintptr_t) maps_tmp->addr_start;
auto end = (uintptr_t) maps_tmp->addr_end;
if (maps_tmp->is_r || maps_tmp->is_x) { // If memory is readable or executable
if (data) {
data = (hide_struct *) realloc(data, sizeof(hide_struct) * (data_count + 1));
} else {
data = (hide_struct *) malloc(sizeof(hide_struct));
}
data[data_count].original = maps_tmp;
data_count += 1;
}
LOGD("%" PRIxPTR"-%" PRIxPTR" %s %ld %s", start, end, maps_tmp->perm, maps_tmp->offset,
maps_tmp->pathname);
}
for (int i = 0; i < data_count; ++i) {
LOGI("do_hide %d", i);
do_hide(&data[i]);
}
// Free backup memory to avoid leaks
for (int i = 0; i < data_count; ++i) {
FAILURE_RETURN(munmap((void *) data[i].backup_address,
(uintptr_t) data[i].original->addr_end - (uintptr_t) data[i].original->addr_start), -1);
}
if (data) free(data);
pmparser_free(maps);
return 0;
}

View File

@@ -0,0 +1,19 @@
//
// Created by Mac on 2024/11/15.
//
#ifndef ZYGISK_MYINJECTOR_NEWRIRUHIDE_H
#define ZYGISK_MYINJECTOR_NEWRIRUHIDE_H
#define EXPORT __attribute__((visibility("default"))) __attribute__((used))
#include <cinttypes>
#include <sys/mman.h>
#include <set>
#include <string_view>
#include "pmparser.h"
#include "android/log.h"
#include "log.h"
extern "C" {
int riru_hide(const char *name) EXPORT;
}
#endif //ZYGISK_MYINJECTOR_NEWRIRUHIDE_H

View File

@@ -0,0 +1,307 @@
/*
@Author : ouadimjamal@gmail.com
@date : December 2015
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. No representations are made about the suitability of this
software for any purpose. It is provided "as is" without express or
implied warranty.
*/
#include "pmparser.h"
#include "log.h"
/**
* gobal variables
*/
//procmaps_struct* g_last_head=NULL;
//procmaps_struct* g_current=NULL;
procmaps_iterator* pmparser_parse(int pid){
LOGI("pmparser_parse called with pid: %d", pid);
procmaps_iterator* maps_it = (procmaps_iterator *)malloc(sizeof(procmaps_iterator));
if (!maps_it) {
LOGI("Failed to allocate memory for procmaps_iterator");
return NULL;
}
LOGI("Allocated memory for procmaps_iterator: %p", maps_it);
char maps_path[500];
if(pid >= 0 ){
snprintf(maps_path, sizeof(maps_path), "/proc/%d/maps", pid);
LOGI("Constructed maps_path for pid: %s", maps_path);
} else {
snprintf(maps_path, sizeof(maps_path), "/proc/self/maps");
LOGI("Constructed maps_path for self: %s", maps_path);
}
FILE* file = fopen(maps_path, "r");
if(!file){
LOGI("pmparser: cannot open the memory maps, %s", strerror(errno));
free(maps_it);
return NULL;
}
LOGI("Opened maps file: %s", maps_path);
int ind = 0;
char buf[PROCMAPS_LINE_MAX_LENGTH];
procmaps_struct* list_maps = NULL;
procmaps_struct* tmp;
procmaps_struct* current_node = NULL;
char addr1[20], addr2[20], perm[8], offset[20], dev[10], inode[30], pathname[PATH_MAX];
while (fgets(buf, PROCMAPS_LINE_MAX_LENGTH, file)) {
LOGI("Read line %d: %s", ind + 1, buf);
// 分配一个新的节点
tmp = (procmaps_struct*)malloc(sizeof(procmaps_struct));
if (!tmp) {
LOGI("Failed to allocate memory for procmaps_struct at line %d", ind + 1);
fclose(file);
// 需要释放已分配的节点,避免内存泄漏
procmaps_struct* iter = list_maps;
while (iter) {
procmaps_struct* next = iter->next;
free(iter);
iter = next;
}
free(maps_it);
return NULL;
}
LOGI("Allocated memory for procmaps_struct: %p", tmp);
// 填充节点
_pmparser_split_line(buf, addr1, addr2, perm, offset, dev, inode, pathname);
LOGI("Parsed line %d - addr1: %s, addr2: %s, perm: %s, offset: %s, dev: %s, inode: %s, pathname: %s",
ind + 1, addr1, addr2, perm, offset, dev, inode, pathname);
// 使用临时变量解析地址
unsigned long tmp_addr_start_ul, tmp_addr_end_ul;
if (sscanf(addr1, "%lx", &tmp_addr_start_ul) != 1) {
LOGI("Failed to parse addr_start at line %d", ind + 1);
free(tmp);
continue;
}
if (sscanf(addr2, "%lx", &tmp_addr_end_ul) != 1) {
LOGI("Failed to parse addr_end at line %d", ind + 1);
free(tmp);
continue;
}
LOGI("Parsed addresses - addr_start: 0x%lx, addr_end: 0x%lx", tmp_addr_start_ul, tmp_addr_end_ul);
tmp->addr_start = (void*)tmp_addr_start_ul;
tmp->addr_end = (void*)tmp_addr_end_ul;
// size
tmp->length = (unsigned long)((char*)tmp->addr_end - (char*)tmp->addr_start);
LOGI("Calculated length: %lu", tmp->length);
// perm
strncpy(tmp->perm, perm, sizeof(tmp->perm) - 1);
tmp->perm[sizeof(tmp->perm) - 1] = '\0';
tmp->is_r = (perm[0] == 'r');
tmp->is_w = (perm[1] == 'w');
tmp->is_x = (perm[2] == 'x');
tmp->is_p = (perm[3] == 'p');
LOGI("Permissions - is_r: %d, is_w: %d, is_x: %d, is_p: %d", tmp->is_r, tmp->is_w, tmp->is_x, tmp->is_p);
// offset
if (sscanf(offset, "%lx", &tmp->offset) != 1) {
LOGI("Failed to parse offset at line %d", ind + 1);
free(tmp);
continue;
}
LOGI("Parsed offset: 0x%lx", tmp->offset);
// device
strncpy(tmp->dev, dev, sizeof(tmp->dev) - 1);
tmp->dev[sizeof(tmp->dev) - 1] = '\0';
LOGI("Device: %s", tmp->dev);
// inode
tmp->inode = atoi(inode);
LOGI("Inode: %d", tmp->inode);
// pathname
strncpy(tmp->pathname, pathname, sizeof(tmp->pathname) - 1);
tmp->pathname[sizeof(tmp->pathname) - 1] = '\0';
LOGI("Pathname: %s", tmp->pathname);
tmp->next = NULL;
// 连接节点到链表
if(ind == 0){
list_maps = tmp;
current_node = list_maps;
LOGI("Initialized list_maps with first node: %p", list_maps);
}
else{
current_node->next = tmp;
current_node = tmp;
LOGI("Appended node to list_maps: %p", tmp);
}
ind++;
}
if (ferror(file)) {
LOGI("Error occurred while reading the maps file");
// 释放已分配的节点和 maps_it
procmaps_struct* iter = list_maps;
while (iter) {
procmaps_struct* next = iter->next;
free(iter);
iter = next;
}
fclose(file);
free(maps_it);
return NULL;
}
// 关闭文件
fclose(file);
LOGI("Closed maps file: %s", maps_path);
// 设置迭代器
maps_it->head = list_maps;
maps_it->current = list_maps;
LOGI("Initialized procmaps_iterator - head: %p, current: %p", maps_it->head, maps_it->current);
return maps_it;
}
procmaps_struct* pmparser_next(procmaps_iterator* p_procmaps_it){
if(p_procmaps_it->current == NULL)
return NULL;
procmaps_struct* p_current = p_procmaps_it->current;
p_procmaps_it->current = p_procmaps_it->current->next;
return p_current;
/*
if(g_current==NULL){
g_current=g_last_head;
}else
g_current=g_current->next;
return g_current;
*/
}
void pmparser_free(procmaps_iterator* p_procmaps_it){
procmaps_struct* maps_list = p_procmaps_it->head;
if(maps_list==NULL) return ;
procmaps_struct* act=maps_list;
procmaps_struct* nxt=act->next;
while(act!=NULL){
free(act);
act=nxt;
if(nxt!=NULL)
nxt=nxt->next;
}
free(p_procmaps_it);
}
void _pmparser_split_line(
char*buf,char*addr1,char*addr2,
char*perm,char* offset,char* device,char*inode,
char* pathname){
//
int orig=0;
int i=0;
//addr1
while(buf[i]!='-'){
addr1[i-orig]=buf[i];
i++;
}
addr1[i]='\0';
i++;
//addr2
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
addr2[i-orig]=buf[i];
i++;
}
addr2[i-orig]='\0';
//perm
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
perm[i-orig]=buf[i];
i++;
}
perm[i-orig]='\0';
//offset
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
offset[i-orig]=buf[i];
i++;
}
offset[i-orig]='\0';
//dev
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
device[i-orig]=buf[i];
i++;
}
device[i-orig]='\0';
//inode
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
inode[i-orig]=buf[i];
i++;
}
inode[i-orig]='\0';
//pathname
pathname[0]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' ' && buf[i]!='\n'){
pathname[i-orig]=buf[i];
i++;
}
pathname[i-orig]='\0';
}
void pmparser_print(procmaps_struct* map, int order){
procmaps_struct* tmp=map;
int id=0;
if(order<0) order=-1;
while(tmp!=NULL){
//(unsigned long) tmp->addr_start;
if(order==id || order==-1){
printf("Backed by:\t%s\n",strlen(tmp->pathname)==0?"[anonym*]":tmp->pathname);
printf("Range:\t\t%p-%p\n",tmp->addr_start,tmp->addr_end);
printf("Length:\t\t%ld\n",tmp->length);
printf("Offset:\t\t%ld\n",tmp->offset);
printf("Permissions:\t%s\n",tmp->perm);
printf("Inode:\t\t%d\n",tmp->inode);
printf("Device:\t\t%s\n",tmp->dev);
}
if(order!=-1 && id>order)
tmp=NULL;
else if(order==-1){
printf("#################################\n");
tmp=tmp->next;
}else tmp=tmp->next;
id++;
}
}

View File

@@ -0,0 +1,99 @@
/*
@Author : ouadimjamal@gmail.com
@date : December 2015
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. No representations are made about the suitability of this
software for any purpose. It is provided "as is" without express or
implied warranty.
*/
#ifndef H_PMPARSER
#define H_PMPARSER
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/limits.h>
//maximum line length in a procmaps file
#define PROCMAPS_LINE_MAX_LENGTH (PATH_MAX + 100)
/**
* procmaps_struct
* @desc hold all the information about an area in the process's VM
*/
typedef struct procmaps_struct{
void* addr_start; //< start address of the area
void* addr_end; //< end address
unsigned long length; //< size of the range
char perm[5]; //< permissions rwxp
short is_r; //< rewrote of perm with short flags
short is_w;
short is_x;
short is_p;
long offset; //< offset
char dev[12]; //< dev major:minor
int inode; //< inode of the file that backs the area
char pathname[600]; //< the path of the file that backs the area
//chained list
struct procmaps_struct* next; //<handler of the chinaed list
} procmaps_struct;
/**
* procmaps_iterator
* @desc holds iterating information
*/
typedef struct procmaps_iterator{
procmaps_struct* head;
procmaps_struct* current;
} procmaps_iterator;
/**
* pmparser_parse
* @param pid the process id whose memory map to be parser. the current process if pid<0
* @return an iterator over all the nodes
*/
procmaps_iterator* pmparser_parse(int pid);
/**
* pmparser_next
* @description move between areas
* @param p_procmaps_it the iterator to move on step in the chained list
* @return a procmaps structure filled with information about this VM area
*/
procmaps_struct* pmparser_next(procmaps_iterator* p_procmaps_it);
/**
* pmparser_free
* @description should be called at the end to free the resources
* @param p_procmaps_it the iterator structure returned by pmparser_parse
*/
void pmparser_free(procmaps_iterator* p_procmaps_it);
/**
* _pmparser_split_line
* @description internal usage
*/
void _pmparser_split_line(char*buf,char*addr1,char*addr2,char*perm, char* offset, char* device,char*inode,char* pathname);
/**
* pmparser_print
* @param map the head of the list
* @order the order of the area to print, -1 to print everything
*/
void pmparser_print(procmaps_struct* map,int order);
#endif