├── CEServer ├── native-api.cpp ├── native-api.h ├── symbols.h ├── context.h ├── IMemReaderWriterProxy.h ├── porthelp.h ├── porthelp.cpp ├── api.h ├── ceserver.h ├── MemoryReaderWriter37.hpp ├── api.cpp ├── symbols.cpp └── main.cpp ├── Cargo.toml ├── .cargo └── config.toml ├── .gitignore ├── cli ├── Cargo.toml └── src │ └── main.rs ├── rwMem ├── ver_control.h ├── Makefile ├── api_proxy.h ├── bp.h ├── sys.h ├── proc_maps.h ├── bp.c ├── phy_mem.h └── sys.c ├── librwmem ├── Cargo.toml ├── src │ ├── errors.rs │ └── lib.rs ├── examples │ └── test.rs └── Cargo.lock ├── patch └── overflow_handler_context.patch ├── README.md └── Cargo.lock /CEServer/native-api.cpp: -------------------------------------------------------------------------------- 1 | #include "native-api.h" 2 | -------------------------------------------------------------------------------- /CEServer/native-api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define MAX_HIT_COUNT 5000000 -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "cli", 5 | "librwmem", 6 | ] 7 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "aarch64-unknown-linux-musl" 3 | 4 | [target.aarch64-unknown-linux-musl] 5 | linker = "ld.lld" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmd 2 | build/ 3 | *.order 4 | *.symvers 5 | *.mod.c 6 | *.o 7 | *.mod 8 | *.ko 9 | *.usyms 10 | .vs/ 11 | Debug/ 12 | x64/ 13 | target/ 14 | .cache/ 15 | compile_commands.json 16 | -------------------------------------------------------------------------------- /CEServer/symbols.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class CSymbols { 3 | public: 4 | //static int GetSymbolListFromFile(char *filename, unsigned char **output); 5 | //static unsigned long long GetModuleSize(char *filename, unsigned long long defaultsize); 6 | 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rwmemctl" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | clap = {version = "^4", features = ["derive"]} 8 | anyhow = "1" 9 | shellish_parse = "2.2" 10 | clap-num = "^1.1" 11 | pretty-hex = "0.4" 12 | hex = "*" 13 | tokio = { version = "1", features = ["rt", "net"] } 14 | librwmem = { path = "../librwmem", features = ["async"]} 15 | 16 | -------------------------------------------------------------------------------- /rwMem/ver_control.h: -------------------------------------------------------------------------------- 1 | #ifndef VERSION_CONTROL_H_ 2 | #define VERSION_CONTROL_H_ 3 | #define DEV_FILENAME "rwmem" //当前驱动DEV文件名 4 | 5 | //直接调用内核API进行用户层数据交换 6 | #define CONFIG_DIRECT_API_USER_COPY 7 | 8 | //打印内核调试信息 9 | //#define CONFIG_DEBUG_PRINTK 10 | 11 | #ifdef CONFIG_DEBUG_PRINTK 12 | #define printk_debug printk 13 | #else 14 | static inline void printk_debug(char *fmt, ...) {} 15 | #endif 16 | 17 | #endif /* VERSION_CONTROL_H_ */ 18 | -------------------------------------------------------------------------------- /rwMem/Makefile: -------------------------------------------------------------------------------- 1 | MODULE_NAME := rwMem 2 | RESMAN_CORE_OBJS:=sys.o bp.o 3 | RESMAN_GLUE_OBJS:= 4 | ifneq ($(KERNELRELEASE),) 5 | $(MODULE_NAME)-objs:=$(RESMAN_GLUE_OBJS) $(RESMAN_CORE_OBJS) 6 | obj-y := rwMem.o 7 | else 8 | ifeq ($(KDIR),) 9 | $(error KDIR is not defined. Please set the KDIR variable.) 10 | endif 11 | all: 12 | make -C $(KDIR) M=$(PWD) ARCH=arm64 SUBARCH=arm64 modules 13 | clean: 14 | rm -f *.ko *.o *.mod.o *.mod.c *.symvers .*.cmd 15 | endif 16 | -------------------------------------------------------------------------------- /librwmem/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "librwmem" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | nix = { version = "0.27", features = ["ioctl", "fs"] } 10 | libc = "0.2" 11 | byteorder = "1.5" 12 | bitvec = "1" 13 | thiserror = "1" 14 | tokio = {version = "1", features = ["net", "rt", "macros"], default-features = false, optional = true} 15 | 16 | [features] 17 | default = ["async"] 18 | async = ["dep:tokio"] 19 | 20 | -------------------------------------------------------------------------------- /CEServer/context.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTEXT_H_ 2 | #define CONTEXT_H_ 3 | #ifdef HAS_LINUX_USER_H 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | #include 10 | #include 11 | 12 | #ifdef __aarch64__ 13 | #include 14 | #endif 15 | 16 | #include 17 | 18 | #ifdef __i386__ 19 | typedef struct user_regs_struct CONTEXT_REGS; 20 | #endif 21 | 22 | #ifdef __x86_64__ 23 | typedef struct user_regs_struct CONTEXT_REGS; 24 | #endif 25 | 26 | #ifdef __arm__ 27 | typedef struct pt_regs CONTEXT_REGS; 28 | #endif 29 | 30 | #ifdef __aarch64__ 31 | typedef struct user_pt_regs CONTEXT_REGS; 32 | #endif 33 | 34 | struct CONTEXT { 35 | CONTEXT_REGS regs; 36 | }; 37 | 38 | #endif /* CONTEXT_H_ */ -------------------------------------------------------------------------------- /librwmem/src/errors.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum Error { 5 | #[error("IO error: {0}")] 6 | Errno(#[from] nix::errno::Errno), 7 | #[error("read too short: expect read {0} bytes, but short {1} bytes")] 8 | ReadFailed(usize, usize), 9 | #[error("write too short: expect write {0} bytes, but short {1} bytes")] 10 | WriteFailed(usize, usize), 11 | #[error("maps too long")] 12 | MapsTooLong, 13 | #[error("maps parse error: {0}")] 14 | MapsParseError(#[from] std::io::Error), 15 | #[error("not aligned")] 16 | NotAligned, 17 | #[error("begin address {0} is larger than end address {1}")] 18 | BeginLargerThanEnd(u64, u64), 19 | #[error("invalid register: {0}")] 20 | InvalidRegister(u64), 21 | #[error("invalid breakpoint type: {0}")] 22 | InvalidBreakpointType(String), 23 | } 24 | -------------------------------------------------------------------------------- /patch/overflow_handler_context.patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h 2 | index 7cc581e0e..78b0accf1 100644 3 | --- a/include/linux/perf_event.h 4 | +++ b/include/linux/perf_event.h 5 | @@ -1096,20 +1096,23 @@ __is_default_overflow_handler(perf_overflow_handler_t overflow_handler) 6 | return true; 7 | return false; 8 | } 9 | 10 | #define is_default_overflow_handler(event) \ 11 | __is_default_overflow_handler((event)->overflow_handler) 12 | 13 | #ifdef CONFIG_BPF_SYSCALL 14 | static inline bool uses_default_overflow_handler(struct perf_event *event) 15 | { 16 | + if(unlikely(((uint64_t)(event->overflow_handler_context) >> 56) == 0xcb)){ 17 | + return true; 18 | + } 19 | if (likely(is_default_overflow_handler(event))) 20 | return true; 21 | 22 | return __is_default_overflow_handler(event->orig_overflow_handler); 23 | } 24 | #else 25 | #define uses_default_overflow_handler(event) \ 26 | is_default_overflow_handler(event) 27 | #endif 28 | 29 | -------------------------------------------------------------------------------- /CEServer/IMemReaderWriterProxy.h: -------------------------------------------------------------------------------- 1 | #ifndef MEM_READER_WRITER_PROXY_H_ 2 | #define MEM_READER_WRITER_PROXY_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include 13 | #include 14 | 15 | typedef int BOOL; 16 | #define TRUE 1 17 | #define FALSE 0 18 | #define PAGE_NOACCESS 1 19 | #define PAGE_READONLY 2 20 | #define PAGE_READWRITE 4 21 | #define PAGE_WRITECOPY 8 22 | #define PAGE_EXECUTE 16 23 | #define PAGE_EXECUTE_READ 32 24 | #define PAGE_EXECUTE_READWRITE 64 25 | 26 | #define MEM_MAPPED 262144 27 | #define MEM_PRIVATE 131072 28 | 29 | #pragma pack(1) 30 | typedef struct { 31 | uint64_t baseaddress; 32 | uint64_t size; 33 | uint32_t protection; 34 | uint32_t type; 35 | char name[4096]; 36 | } DRIVER_REGION_INFO, *PDRIVER_REGION_INFO; 37 | #pragma pack() 38 | 39 | #endif /* MEM_READER_WRITER_PROXY_H_ */ 40 | -------------------------------------------------------------------------------- /librwmem/examples/test.rs: -------------------------------------------------------------------------------- 1 | use librwmem::{BreakpointType, Device, DEFAULT_DRIVER_PATH}; 2 | 3 | #[tokio::main(flavor = "current_thread")] 4 | async fn main() -> Result<(), Box> { 5 | let device = Device::new(DEFAULT_DRIVER_PATH)?; 6 | let pid = 0x1234; 7 | let addr = 0x12345678; 8 | 9 | // write to remote process memory 10 | device.write_mem(pid, addr, &[0xcc, 0xcc, 0xcc, 0xcc])?; 11 | 12 | // read from remote process memory 13 | let mut buf = [0u8; 1024]; 14 | device.read_mem(pid, addr, &mut buf)?; 15 | 16 | // add a breakpoint 17 | let bp = device.add_bp(pid, BreakpointType::ReadWrite, 8, addr)?; 18 | 19 | // wait for the breakpoint to be hit 20 | bp.wait().await?; 21 | 22 | // print the registers 23 | println!("{:x?}", bp.get_regs()?); 24 | 25 | // set the registers, set X8 to 0 26 | bp.set_reg(8, 0)?; 27 | 28 | // run a single instruction 29 | bp.step()?; 30 | bp.wait().await?; 31 | 32 | // continue the process 33 | bp.cont()?; 34 | 35 | // remove the breakpoint 36 | std::mem::drop(bp); 37 | Ok(()) 38 | } 39 | -------------------------------------------------------------------------------- /rwMem/api_proxy.h: -------------------------------------------------------------------------------- 1 | #ifndef API_PROXY_H_ 2 | #define API_PROXY_H_ 3 | // clang-format off 4 | #include 5 | #include 6 | // clang-format on 7 | #include 8 | #include 9 | #include 10 | 11 | static __always_inline unsigned long x_copy_from_user(void *to, const void __user *from, unsigned long n) { 12 | #ifdef CONFIG_DIRECT_API_USER_COPY 13 | unsigned long __arch_copy_from_user(void *to, const void __user *from, unsigned long n); 14 | return __arch_copy_from_user(to, from, n); 15 | #else 16 | return copy_from_user(to, from, n); 17 | #endif 18 | } 19 | static __always_inline unsigned long x_copy_to_user(void __user *to, const void *from, unsigned long n) { 20 | #ifdef CONFIG_DIRECT_API_USER_COPY 21 | unsigned long __arch_copy_to_user(void __user *to, const void *from, unsigned long n); 22 | return __arch_copy_to_user(to, from, n); 23 | #else 24 | return copy_to_user(to, from, n); 25 | #endif 26 | } 27 | 28 | static __always_inline long x_probe_kernel_read(void *bounce, const char *ptr, size_t sz) { 29 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) 30 | return copy_from_kernel_nofault(bounce, ptr, sz); 31 | #else 32 | return probe_kernel_read(bounce, ptr, sz); 33 | #endif 34 | } 35 | 36 | #endif /* API_PROXY_H_ */ 37 | -------------------------------------------------------------------------------- /rwMem/bp.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_RWMEM_BP_H_ 2 | #define _KERNEL_RWMEM_BP_H_ 3 | 4 | #include "linux/perf_event.h" 5 | #include "linux/fs.h" 6 | #include "linux/spinlock_types.h" 7 | 8 | #define RWMEM_BP_MAJOR_NUM 101 9 | 10 | struct set_reg_param { 11 | uint64_t id; 12 | uint64_t value; 13 | }; 14 | struct set_simd_reg_param { 15 | uint64_t id; 16 | __uint128_t value; 17 | }; 18 | 19 | #define IOCTL_BP_CONTINUE _IO(RWMEM_BP_MAJOR_NUM, 0) 20 | #define IOCTL_BP_SET_REG _IOW(RWMEM_BP_MAJOR_NUM, 1, struct set_reg_param) 21 | #define IOCTL_BP_SET_SIMD_REG \ 22 | _IOW(RWMEM_BP_MAJOR_NUM, 2, struct set_simd_reg_param) 23 | #define IOCTL_BP_STEP _IO(RWMEM_BP_MAJOR_NUM, 3) 24 | #define IOCTL_BP_IS_STOPPED _IO(RWMEM_BP_MAJOR_NUM, 4) 25 | 26 | void bp_callback(struct perf_event *perf, struct perf_sample_data *sample_data, 27 | struct pt_regs *regs); 28 | int rwmem_bp_step_handler(struct pt_regs *regs, unsigned long esr); 29 | 30 | struct rwmem_bp_private_data { 31 | struct perf_event *event; 32 | struct task_struct *target_task; 33 | struct wait_queue_head wq; 34 | struct wait_queue_head poll_wq; 35 | atomic_t poll; 36 | struct fasync_struct *fasync; 37 | struct spinlock flag_lock; 38 | bool continue_flag; 39 | bool stopped_flag; 40 | }; 41 | 42 | struct file *create_rwmem_bp_file(void); 43 | #endif -------------------------------------------------------------------------------- /CEServer/porthelp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef int32_t HANDLE; // just an int, in case of a 32-bit ce version and a 64-bit linux version I can not give pointers, so use ID's for handles 5 | typedef int32_t DWORD; 6 | 7 | #define TH32CS_SNAPPROCESS 0x2 8 | #define TH32CS_SNAPTHREAD 0x4 9 | #define TH32CS_SNAPMODULE 0x8 10 | 11 | #define PAGE_NOACCESS 1 12 | #define PAGE_READONLY 2 13 | #define PAGE_READWRITE 4 14 | #define PAGE_WRITECOPY 8 15 | #define PAGE_EXECUTE 16 16 | #define PAGE_EXECUTE_READ 32 17 | #define PAGE_EXECUTE_READWRITE 64 18 | 19 | #define MEM_MAPPED 262144 20 | #define MEM_PRIVATE 131072 21 | 22 | #define TRUE 1 23 | #define FALSE 0 24 | 25 | typedef enum { 26 | htEmpty = 0, 27 | htProcesHandle, 28 | htThreadHandle, 29 | htTHSProcess, 30 | htTHSModule, 31 | htTHSThread, 32 | htNativeThreadHandle 33 | } handleType; // The difference between ThreadHandle and NativeThreadHandle is that threadhandle is based on the processid of the thread, the NativeThreadHandle is in linux usually 34 | // the pthread_t handle 35 | 36 | typedef int BOOL; 37 | 38 | class CPortHelper { 39 | public: 40 | static HANDLE CreateHandleFromPointer(uint64_t p, handleType type); 41 | static handleType GetHandleType(HANDLE handle); 42 | static uint64_t GetPointerFromHandle(HANDLE handle); 43 | static void RemoveHandle(HANDLE handle); 44 | static HANDLE FindHandleByPID(DWORD pid); 45 | }; 46 | -------------------------------------------------------------------------------- /rwMem/sys.h: -------------------------------------------------------------------------------- 1 | #ifndef _KERNEL_RWMEM_SYS_H_ 2 | #define _KERNEL_RWMEM_SYS_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define RWMEM_MAJOR_NUM 100 22 | 23 | #define IOCTL_GET_PROCESS_MAPS_COUNT _IOW(RWMEM_MAJOR_NUM, 0, size_t) 24 | #define IOCTL_GET_PROCESS_MAPS_LIST _IOWR(RWMEM_MAJOR_NUM, 1, char *) 25 | #define IOCTL_CHECK_PROCESS_ADDR_PHY _IOWR(RWMEM_MAJOR_NUM, 2, char *) 26 | #define IOCTL_ADD_BP _IOWR(RWMEM_MAJOR_NUM, 3, char *) 27 | #define IOCTL_GET_NUM_BRPS _IO(RWMEM_MAJOR_NUM, 4) 28 | #define IOCTL_GET_NUM_WRPS _IO(RWMEM_MAJOR_NUM, 5) 29 | 30 | struct init_device_info { 31 | char proc_self_status[4096]; 32 | int proc_self_maps_cnt; 33 | }; 34 | 35 | static int g_rwProcMem_major = 0; 36 | static dev_t g_rwProcMem_devno; 37 | 38 | // rwProcMemDev设备结构体 39 | struct rwmem_dev { 40 | struct cdev *pcdev; 41 | }; 42 | static struct rwmem_dev *g_rwProcMem_devp; 43 | 44 | static struct class *g_Class_devp; 45 | 46 | int rwmem_open(struct inode *inode, struct file *filp); 47 | int rwmem_release(struct inode *inode, struct file *filp); 48 | ssize_t rwmem_read(struct file *filp, char __user *buf, size_t size, 49 | loff_t *ppos); 50 | ssize_t rwmem_write(struct file *filp, const char __user *buf, size_t size, 51 | loff_t *ppos); 52 | long rwmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 53 | 54 | static const struct file_operations rwmem_fops = { 55 | .owner = THIS_MODULE, 56 | 57 | .read = rwmem_read, 58 | .write = rwmem_write, 59 | .llseek = no_llseek, 60 | .unlocked_ioctl = rwmem_ioctl, 61 | .open = rwmem_open, 62 | .release = rwmem_release, 63 | }; 64 | 65 | #endif -------------------------------------------------------------------------------- /CEServer/porthelp.cpp: -------------------------------------------------------------------------------- 1 | #include "porthelp.h" 2 | #include "api.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | struct HANDLE_INFO { 11 | uint64_t p; // TODO:这里有空再搞成shared_ptr派生成各个基类,防止内存泄漏 12 | handleType type; 13 | }; 14 | std::map m_HandlePointList; 15 | 16 | HANDLE CPortHelper::CreateHandleFromPointer(uint64_t p, handleType type) { 17 | std::random_device rd; 18 | HANDLE handle = 10000 + rd() / 1000; 19 | handle = handle < 0 ? -handle : handle; 20 | while (m_HandlePointList.find(handle) != m_HandlePointList.end()) { 21 | handle = 10000 + rd() / 1000; 22 | handle = handle < 0 ? -handle : handle; 23 | } 24 | 25 | HANDLE_INFO hinfo = {0}; 26 | hinfo.p = p; 27 | hinfo.type = type; 28 | m_HandlePointList.insert(std::pair(handle, hinfo)); 29 | 30 | return handle; 31 | } 32 | 33 | handleType CPortHelper::GetHandleType(HANDLE handle) { 34 | auto iter = m_HandlePointList.find(handle); 35 | if (iter == m_HandlePointList.end()) { 36 | return htEmpty; 37 | } 38 | return iter->second.type; 39 | } 40 | 41 | uint64_t CPortHelper::GetPointerFromHandle(HANDLE handle) { 42 | auto iter = m_HandlePointList.find(handle); 43 | if (iter == m_HandlePointList.end()) { 44 | return 0; 45 | } 46 | return iter->second.p; 47 | } 48 | 49 | void CPortHelper::RemoveHandle(HANDLE handle) { 50 | auto iter = m_HandlePointList.find(handle); 51 | if (iter == m_HandlePointList.end()) { 52 | return; 53 | } 54 | m_HandlePointList.erase(iter); 55 | } 56 | 57 | HANDLE CPortHelper::FindHandleByPID(DWORD pid) { 58 | for (auto item = m_HandlePointList.begin(); item != m_HandlePointList.end(); item++) { 59 | if (item->second.type == htProcesHandle) { 60 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)item->second.p; 61 | if (pCeOpenProcess->pid == pid) { 62 | return item->first; 63 | } 64 | } 65 | } 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /CEServer/api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MemoryReaderWriter37.hpp" 3 | #include "context.h" 4 | #include "porthelp.h" 5 | #include 6 | #include 7 | #include 8 | /* 9 | 10 | #if defined(__arm__) || defined(__ANDROID__) 11 | #include 12 | #else 13 | #include 14 | #endif 15 | */ 16 | 17 | #ifdef HAS_LINUX_USER_H 18 | #include 19 | #else 20 | #include 21 | #endif 22 | 23 | #include 24 | 25 | #define VQE_PAGEDONLY 1 26 | #define VQE_DIRTYONLY 2 27 | #define VQE_NOSHARED 4 28 | 29 | struct ModuleListEntry { 30 | unsigned long long baseAddress; 31 | int moduleSize; 32 | std::string moduleName; 33 | }; 34 | 35 | struct ProcessListEntry { 36 | int PID; 37 | std::string ProcessName; 38 | }; 39 | 40 | #pragma pack(1) 41 | struct RegionInfo { 42 | uint64_t baseaddress; 43 | uint64_t size; 44 | uint32_t protection; 45 | uint32_t type; 46 | }; 47 | #pragma pack() 48 | 49 | struct MyProcessInfo { 50 | int pid; 51 | size_t total_rss; 52 | std::string cmdline; 53 | }; 54 | 55 | struct CeProcessList { 56 | std::vector vProcessList; 57 | decltype(vProcessList)::iterator readIter; 58 | }; 59 | 60 | struct CeModuleList { 61 | std::vector vModuleList; 62 | decltype(vModuleList)::iterator readIter; 63 | }; 64 | 65 | struct CeOpenProcess { 66 | int pid; 67 | uint64_t u64DriverProcessHandle; 68 | 69 | // 短时间内保留上次获取的内存Maps,避免频繁调用驱动获取 70 | std::mutex mtxLockLastMaps; // 访问冲突锁 71 | std::vector vLastMaps; 72 | std::atomic nLastGetMapsTime; 73 | }; 74 | 75 | class CApi { 76 | public: 77 | static BOOL InitReadWriteDriver(const char *lpszDevFileName, BOOL bUseBypassSELinuxMode); 78 | static HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID); 79 | static BOOL Process32First(HANDLE hSnapshot, ProcessListEntry &processentry); 80 | static BOOL Process32Next(HANDLE hSnapshot, ProcessListEntry &processentry); 81 | static BOOL Module32First(HANDLE hSnapshot, ModuleListEntry &moduleentry); 82 | static BOOL Module32Next(HANDLE hSnapshot, ModuleListEntry &moduleentry); 83 | static HANDLE OpenProcess(DWORD pid); 84 | static void CloseHandle(HANDLE h); 85 | static int VirtualQueryExFull(HANDLE hProcess, uint32_t flags, std::vector &vRinfo); 86 | static int VirtualQueryEx(HANDLE hProcess, uint64_t lpAddress, RegionInfo &rinfo, std::string &memName); 87 | static int ReadProcessMemory(HANDLE hProcess, void *lpAddress, void *buffer, int size); 88 | static int WriteProcessMemory(HANDLE hProcess, void *lpAddress, void *buffer, int size); 89 | 90 | protected: 91 | }; 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RwMem 2 | 3 | A modified kernel to read and write memory and set hardware breakpoint in a remote process. 4 | 5 | ## Features 6 | 7 | 1. read and write memory 8 | 2. set hardware breakpoint and memory watchpoint 9 | 3. suspend the remote process when the breakpoint or watchpoint is hit 10 | 4. run the remote process instruction by instruction 11 | 5. get and set the register value 12 | 13 | ## Why? 14 | 15 | There are many ways to do this, but most of them are not very reliable. This modified kernel is a reliable and easy way to read and write memory and set hardware breakpoint in a remote process. 16 | 17 | **Why not ptrace?** `ptrace` is a good way to debug a process, but it has some limitations. For example, the target process can easily detect the debugger. 18 | 19 | **Why not uprobe?** `uprobe` is a good way to set breakpoint, but it will modify the memory of target instruction. Also it can not set watchpoint. [More details](https://www.cnxct.com/defeating-ebpf-uprobe-monitoring/#ftoc-heading-14) 20 | 21 | ## Example 22 | 23 | ```rust 24 | use librwmem::{BreakpointType, Device, DEFAULT_DRIVER_PATH}; 25 | 26 | let device = Device::new(DEFAULT_DRIVER_PATH)?; 27 | let pid = 0x1234; 28 | let addr = 0x12345678; 29 | 30 | // write to remote process memory 31 | device.write_mem(pid, addr, &[0xcc, 0xcc, 0xcc, 0xcc])?; 32 | 33 | // read from remote process memory 34 | let mut buf = [0u8; 1024]; 35 | device.read_mem(pid, addr, &mut buf)?; 36 | 37 | // add a breakpoint 38 | let bp = device.add_bp(pid, BreakpointType::ReadWrite, 8, addr)?; 39 | 40 | // wait for the breakpoint to be hit 41 | bp.wait().await?; 42 | 43 | // print the registers 44 | println!("{:x?}", bp.get_regs()?); 45 | 46 | // set the registers, set X8 to 0 47 | bp.set_reg(8, 0)?; 48 | 49 | // run a single instruction 50 | bp.step()?; 51 | bp.wait().await?; 52 | 53 | // continue the process 54 | bp.cont()?; 55 | 56 | // remove the breakpoint 57 | std::mem::drop(bp); 58 | ``` 59 | 60 | ## How to build? 61 | 62 | ### Kernel module 63 | 64 | 1. Build the android kernel according to the [KernelSU document](https://kernelsu.org/guide/how-to-build.html) 65 | 2. Apply patches in `patch` folder 66 | 3. Copy the `rwMem` folder to the `drivers` folder in the kernel source code 67 | 4. Add a line `obj-$(CONFIG_RW_MEM) += rwMem/` to the end of `drivers/Makefile` 68 | 5. Build the kernel again 69 | 70 | ### CEServer 71 | 72 | The CEServer is a modified version of the official CEServer. It support the **master** branch of Cheat Engine. 73 | 74 | ```bash 75 | aarch64-linux-gnu-g++ *.cpp -lz -o CEServer 76 | ``` 77 | 78 | ### CLI tool 79 | 80 | ```bash 81 | cargo build --release --target aarch64-unknown-linux-musl 82 | ``` 83 | 84 | ## How to use? 85 | 86 | Install the kernel module and the run the CEServer on your android device. 87 | 88 | You can also use the librwmem to communicate with the kernel module. 89 | 90 | ## Project Structure 91 | 92 | ``` 93 | . 94 | ├── rwMem # The kernel module 95 | ├── patch # Some patches for the kernel 96 | ├── CEServer # A modified CEServer which uses the kernel module to read and write memory 97 | ├── librwmem # A rust library to communicate with the kernel module 98 | └── cli # A cli tool for developers 99 | ``` 100 | 101 | # Acknowledgements 102 | 103 | `librwmem` is inspired and modified by [rwMwmProc33](https://github.com/abcz316/rwProcMem33). 104 | 105 | `KernelSU` is a great project to build a custom kernel for android. 106 | -------------------------------------------------------------------------------- /CEServer/ceserver.h: -------------------------------------------------------------------------------- 1 | #ifndef CESERVER_H_ 2 | #define CESERVER_H_ 3 | 4 | #include "porthelp.h" 5 | #include 6 | #include 7 | 8 | #define CMD_GETVERSION 0 9 | #define CMD_CLOSECONNECTION 1 10 | #define CMD_TERMINATESERVER 2 11 | #define CMD_OPENPROCESS 3 12 | #define CMD_CREATETOOLHELP32SNAPSHOT 4 13 | #define CMD_PROCESS32FIRST 5 14 | #define CMD_PROCESS32NEXT 6 15 | #define CMD_CLOSEHANDLE 7 16 | #define CMD_VIRTUALQUERYEX 8 17 | #define CMD_READPROCESSMEMORY 9 18 | #define CMD_WRITEPROCESSMEMORY 10 19 | #define CMD_STARTDEBUG 11 20 | #define CMD_STOPDEBUG 12 21 | #define CMD_WAITFORDEBUGEVENT 13 22 | #define CMD_CONTINUEFROMDEBUGEVENT 14 23 | #define CMD_SETBREAKPOINT 15 24 | #define CMD_REMOVEBREAKPOINT 16 25 | #define CMD_SUSPENDTHREAD 17 26 | #define CMD_RESUMETHREAD 18 27 | #define CMD_GETTHREADCONTEXT 19 28 | #define CMD_SETTHREADCONTEXT 20 29 | #define CMD_GETARCHITECTURE 21 30 | #define CMD_MODULE32FIRST 22 31 | #define CMD_MODULE32NEXT 23 32 | 33 | #define CMD_GETSYMBOLLISTFROMFILE 24 34 | #define CMD_LOADEXTENSION 25 35 | 36 | #define CMD_ALLOC 26 37 | #define CMD_FREE 27 38 | #define CMD_CREATETHREAD 28 39 | #define CMD_LOADMODULE 29 40 | #define CMD_SPEEDHACK_SETSPEED 30 41 | 42 | #define CMD_VIRTUALQUERYEXFULL 31 43 | #define CMD_GETREGIONINFO 32 44 | #define CMD_GETABI 33 45 | // 4 46 | #define CMD_SET_CONNECTION_NAME 34 47 | 48 | #define CMD_CREATETOOLHELP32SNAPSHOTEX 35 49 | 50 | #define CMD_CHANGEMEMORYPROTECTION 36 51 | 52 | #define CMD_GETOPTIONS 37 53 | #define CMD_GETOPTIONVALUE 38 54 | #define CMD_SETOPTIONVALUE 39 55 | 56 | // when injection won't work but ptrace does: 57 | #define CMD_PTRACE_MMAP 40 58 | 59 | // returns a fake filehandle to be used by CE (handled by the internal handle list) 60 | #define CMD_OPENNAMEDPIPE 41 61 | #define CMD_PIPEREAD 42 62 | #define CMD_PIPEWRITE 43 63 | 64 | #define CMD_GETCESERVERPATH 44 65 | #define CMD_ISANDROID 45 66 | 67 | #define CMD_LOADMODULEEX 46 68 | 69 | #define CMD_SETCURRENTPATH 47 70 | #define CMD_GETCURRENTPATH 48 71 | #define CMD_ENUMFILES 49 72 | #define CMD_GETFILEPERMISSIONS 50 73 | #define CMD_SETFILEPERMISSIONS 51 74 | #define CMD_GETFILE 52 75 | #define CMD_PUTFILE 53 76 | #define CMD_CREATEDIR 54 77 | #define CMD_DELETEFILE 55 78 | 79 | #define CMD_AOBSCAN 200 80 | 81 | // just in case I ever get over 255 commands this value will be reserved for a secondary command list (FF 00 - FF 01 - ... - FF FE - FF FF 01 - FF FF 02 - ..... 82 | #define CMD_COMMANDLIST2 255 83 | 84 | // extern char *versionstring; 85 | 86 | #pragma pack(1) 87 | struct CeVersion { 88 | int version; 89 | unsigned char stringsize; 90 | // append the versionstring 91 | }; 92 | 93 | struct CeCreateToolhelp32Snapshot { 94 | DWORD dwFlags; 95 | DWORD th32ProcessID; 96 | }; 97 | 98 | struct CeProcessEntry { 99 | int result; 100 | int pid; 101 | int processnamesize; 102 | // processname 103 | }; 104 | 105 | typedef struct { 106 | int ReferenceCount; 107 | int threadListIterator; 108 | int threadCount; 109 | int *threadList; 110 | } ThreadList, *PThreadList; 111 | 112 | struct CeModuleEntry { 113 | int32_t result; 114 | int64_t modulebase; 115 | int32_t modulepart; 116 | int32_t modulesize; 117 | uint32_t modulefileoffset; 118 | int32_t modulenamesize; 119 | }; 120 | 121 | struct CeVirtualQueryExInput { 122 | int handle; 123 | uint64_t baseaddress; 124 | }; 125 | 126 | struct CeVirtualQueryExOutput { 127 | uint8_t result; 128 | uint32_t protection; 129 | uint32_t type; 130 | uint64_t baseaddress; 131 | uint64_t size; 132 | }; 133 | 134 | struct CeVirtualQueryExFullInput { 135 | int handle; 136 | uint8_t flags; 137 | }; 138 | 139 | struct CeVirtualQueryExFullOutput { 140 | uint32_t protection; 141 | uint32_t type; 142 | uint64_t baseaddress; 143 | uint64_t size; 144 | }; 145 | 146 | struct CeReadProcessMemoryInput { 147 | uint32_t handle; 148 | uint64_t address; 149 | uint32_t size; 150 | uint8_t compress; 151 | }; 152 | 153 | struct CeReadProcessMemoryOutput { 154 | int read; 155 | }; 156 | 157 | struct CeWriteProcessMemoryInput { 158 | int32_t handle; 159 | int64_t address; 160 | int32_t size; 161 | }; 162 | 163 | struct CeWriteProcessMemoryOutput { 164 | int32_t written; 165 | }; 166 | 167 | struct CeSetBreapointInput { 168 | HANDLE hProcess; 169 | int tid; 170 | int debugreg; 171 | uint64_t Address; 172 | int bptype; 173 | int bpsize; 174 | }; 175 | 176 | struct CeSetBreapointOutput { 177 | int result; 178 | }; 179 | 180 | struct CeRemoveBreapointInput { 181 | HANDLE hProcess; 182 | uint32_t tid; 183 | uint32_t debugreg; 184 | uint32_t wasWatchpoint; 185 | }; 186 | 187 | struct CeRemoveBreapointOutput { 188 | int result; 189 | }; 190 | 191 | struct CeSuspendThreadInput { 192 | HANDLE hProcess; 193 | int tid; 194 | }; 195 | 196 | struct CeSuspendThreadOutput { 197 | int result; 198 | }; 199 | 200 | struct CeResumeThreadInput { 201 | HANDLE hProcess; 202 | int tid; 203 | }; 204 | 205 | struct CeResumeThreadOutput { 206 | int result; 207 | }; 208 | 209 | struct CeAllocInput { 210 | HANDLE hProcess; 211 | uint64_t preferedBase; 212 | uint32_t size; 213 | uint32_t windowsprotection; 214 | }; 215 | 216 | struct CeAllocOutput { 217 | uint64_t address; // 0=fail 218 | }; 219 | 220 | struct CeFreeInput { 221 | HANDLE hProcess; 222 | uint64_t address; 223 | uint32_t size; 224 | }; 225 | 226 | struct CeFreeOutput { 227 | uint32_t result; 228 | }; 229 | 230 | struct CeCreateThreadInput { 231 | HANDLE hProcess; 232 | uint64_t startaddress; 233 | uint64_t parameter; 234 | }; 235 | 236 | struct CeCreateThreadOutput { 237 | HANDLE threadhandle; 238 | }; 239 | 240 | struct CeLoadModuleInput { 241 | HANDLE hProcess; 242 | uint32_t modulepathlength; 243 | // modulepath 244 | }; 245 | 246 | struct CeLoadModuleOutput { 247 | uint32_t result; 248 | }; 249 | 250 | struct CeSpeedhackSetSpeedInput { 251 | HANDLE hProcess; 252 | float speed; 253 | }; 254 | 255 | struct CeSpeedhackSetSpeedOutput { 256 | uint32_t result; 257 | }; 258 | 259 | struct CeAobScanInput { 260 | HANDLE hProcess; 261 | uint64_t start; 262 | uint64_t end; 263 | int inc; 264 | int protection; 265 | int scansize; 266 | }; 267 | #pragma pack() 268 | 269 | #endif /* CESERVER_H_ */ -------------------------------------------------------------------------------- /cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashMap, io::Write}; 2 | 3 | use clap::{Parser, Subcommand}; 4 | use clap_num::maybe_hex; 5 | use librwmem::{Breakpoint, BreakpointType, Device}; 6 | 7 | #[derive(Parser)] 8 | struct Cli { 9 | #[command(subcommand)] 10 | command: Commands, 11 | } 12 | 13 | #[derive(Subcommand)] 14 | enum Commands { 15 | AddBp { 16 | pid: i32, 17 | #[clap(value_parser=clap::value_parser!(BreakpointType))] 18 | bp_type: BreakpointType, 19 | len: u8, 20 | #[clap(value_parser=maybe_hex::)] 21 | addr: u64, 22 | }, 23 | DelBp { 24 | id: i32, 25 | }, 26 | Continue { 27 | id: i32, 28 | }, 29 | SetReg { 30 | id: i32, 31 | #[clap(value_parser=maybe_hex::)] 32 | reg_id: u8, 33 | #[clap(value_parser=maybe_hex::)] 34 | value: u64, 35 | }, 36 | SetSimdReg { 37 | id: i32, 38 | #[clap(value_parser=maybe_hex::)] 39 | reg_id: u8, 40 | #[clap(value_parser=maybe_hex::)] 41 | value: u128, 42 | }, 43 | GetRegs { 44 | id: i32, 45 | #[clap(short)] 46 | simd: bool, 47 | }, 48 | Wait { 49 | id: i32, 50 | }, 51 | GetMemMap { 52 | pid: i32, 53 | }, 54 | WriteMem { 55 | pid: i32, 56 | #[clap(value_parser=maybe_hex::)] 57 | addr: u64, 58 | #[clap(value_parser=clap::value_parser!(MyBytes))] 59 | value: MyBytes, 60 | }, 61 | ReadMem { 62 | pid: i32, 63 | #[clap(value_parser=maybe_hex::)] 64 | addr: u64, 65 | #[clap(value_parser=maybe_hex::)] 66 | size: u64, 67 | }, 68 | Step { 69 | id: i32, 70 | }, 71 | IsStopped { 72 | id: i32, 73 | }, 74 | } 75 | 76 | #[derive(Debug, Clone)] 77 | struct MyBytes(Vec); 78 | impl std::str::FromStr for MyBytes { 79 | type Err = String; 80 | fn from_str(s: &str) -> Result { 81 | hex::decode(s).map_err(|e| e.to_string()).map(MyBytes) 82 | } 83 | } 84 | 85 | fn run_cmd( 86 | cmd: Commands, 87 | device: &Device, 88 | bps: &mut HashMap, 89 | ) -> anyhow::Result<()> { 90 | match cmd { 91 | Commands::AddBp { 92 | pid, 93 | bp_type, 94 | len, 95 | addr, 96 | } => { 97 | let bp = device.add_bp(pid, bp_type, len, addr)?; 98 | let id = bp.as_raw_fd(); 99 | bps.insert(id, bp); 100 | println!("Breakpoint added: {:?}", id); 101 | } 102 | Commands::DelBp { id } => { 103 | let bp = bps 104 | .remove(&id) 105 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 106 | std::mem::drop(bp); 107 | } 108 | Commands::Continue { id } => { 109 | let bp = bps 110 | .get(&id) 111 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 112 | bp.cont()?; 113 | } 114 | Commands::SetReg { id, reg_id, value } => { 115 | let bp = bps 116 | .get(&id) 117 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 118 | bp.set_reg(reg_id, value)?; 119 | } 120 | Commands::SetSimdReg { id, reg_id, value } => { 121 | let bp = bps 122 | .get(&id) 123 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 124 | bp.set_simd_reg(reg_id, value)?; 125 | } 126 | Commands::GetRegs { id, simd } => { 127 | let bp = bps 128 | .get(&id) 129 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 130 | if simd { 131 | let regs = bp.get_regs_with_simd()?; 132 | println!("Hit breakpoint: {:#?}", regs); 133 | } else { 134 | let regs = bp.get_regs()?; 135 | println!("Hit breakpoint: {:#?}", regs); 136 | } 137 | } 138 | Commands::Wait { id } => { 139 | let bp = bps 140 | .get(&id) 141 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 142 | tokio::runtime::Builder::new_current_thread() 143 | .enable_io() 144 | .build()? 145 | .block_on(async { 146 | bp.wait().await?; 147 | Result::<(), librwmem::errors::Error>::Ok(()) 148 | })?; 149 | } 150 | Commands::GetMemMap { pid } => { 151 | let map = device.get_mem_map(pid, true)?; 152 | println!("Memory map: {:#?}", map); 153 | } 154 | Commands::WriteMem { pid, addr, value } => { 155 | device.write_mem(pid, addr, &value.0)?; 156 | } 157 | Commands::ReadMem { pid, addr, size } => { 158 | let mut buf = vec![0u8; size as usize]; 159 | device.read_mem(pid, addr, &mut buf)?; 160 | println!("Data:\n{}", pretty_hex::pretty_hex(&buf)); 161 | } 162 | Commands::Step { id } => { 163 | let bp = bps 164 | .get(&id) 165 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 166 | bp.step()?; 167 | } 168 | Commands::IsStopped { id } => { 169 | let bp = bps 170 | .get(&id) 171 | .ok_or_else(|| anyhow::anyhow!("Breakpoint not found"))?; 172 | let stopped = bp.is_stopped()?; 173 | println!("Stopped: {:?}", stopped); 174 | } 175 | } 176 | Ok(()) 177 | } 178 | 179 | fn read_and_run(device: &Device, bps: &mut HashMap) -> anyhow::Result<()> { 180 | print!("> "); 181 | std::io::stdout().flush().unwrap(); 182 | let mut line = String::new(); 183 | std::io::stdin().read_line(&mut line)?; 184 | if line.trim().is_empty() { 185 | println!(); 186 | return Ok(()); 187 | } 188 | let mut ast = shellish_parse::parse(&line, false)?; 189 | ast.insert(0, "rwmem".to_string()); 190 | let cli = Cli::try_parse_from(&ast)?; 191 | 192 | if let Err(e) = run_cmd(cli.command, device, bps) { 193 | eprintln!("Error: {:?}", e); 194 | } 195 | Ok(()) 196 | } 197 | 198 | fn main() -> anyhow::Result<()> { 199 | let device = Device::new(librwmem::DEFAULT_DRIVER_PATH).unwrap(); 200 | println!("Brps: {:?}", device.get_num_brps()); 201 | println!("Wrps: {:?}", device.get_num_wrps()); 202 | let mut bps: HashMap = HashMap::new(); 203 | loop { 204 | if let Err(e) = read_and_run(&device, &mut bps) { 205 | eprintln!("Error: {:?}", e); 206 | }; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /rwMem/proc_maps.h: -------------------------------------------------------------------------------- 1 | #ifndef PROC_MAPS_H_ 2 | #define PROC_MAPS_H_ 3 | 4 | #include "linux/mm.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "api_proxy.h" 20 | #include "ver_control.h" 21 | 22 | 23 | #if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,43) 24 | #define MM_STRUCT_MMAP_LOCK mmap_sem 25 | #else 26 | #define MM_STRUCT_MMAP_LOCK mmap_lock 27 | #endif 28 | 29 | #define MY_PATH_MAX_LEN 512 30 | 31 | static inline size_t get_proc_map_count(struct pid* proc_pid_struct) { 32 | struct mm_struct *mm; 33 | size_t count = 0; 34 | struct task_struct *task = pid_task(proc_pid_struct, PIDTYPE_PID); 35 | if (!task) { 36 | return 0; 37 | } 38 | mm = get_task_mm(task); 39 | if (!mm) { 40 | return 0; 41 | } 42 | 43 | down_read(&mm->MM_STRUCT_MMAP_LOCK); 44 | count = mm->map_count; 45 | up_read(&mm->MM_STRUCT_MMAP_LOCK); 46 | 47 | mmput(mm); 48 | return count; 49 | } 50 | 51 | 52 | static inline int check_proc_map_can_read(struct pid* proc_pid_struct, size_t proc_virt_addr, size_t size) { 53 | struct task_struct *task = pid_task(proc_pid_struct, PIDTYPE_PID); 54 | struct mm_struct *mm; 55 | struct vm_area_struct *vma; 56 | int res = 0; 57 | if (!task) { return res; } 58 | 59 | mm = get_task_mm(task); 60 | 61 | if (!mm) { return res; } 62 | 63 | down_read(&mm->MM_STRUCT_MMAP_LOCK); 64 | 65 | vma = find_vma(mm, proc_virt_addr); 66 | if (vma) { 67 | if (vma->vm_flags & VM_READ) { 68 | size_t read_end = proc_virt_addr + size; 69 | if (read_end <= vma->vm_end) { 70 | res = 1; 71 | } 72 | } 73 | } 74 | up_read(&mm->MM_STRUCT_MMAP_LOCK); 75 | 76 | mmput(mm); 77 | return res; 78 | } 79 | static inline int check_proc_map_can_write(struct pid* proc_pid_struct, size_t proc_virt_addr, size_t size) { 80 | struct task_struct *task = pid_task(proc_pid_struct, PIDTYPE_PID); 81 | struct mm_struct *mm; 82 | struct vm_area_struct *vma; 83 | int res = 0; 84 | 85 | if (!task) { return res; } 86 | 87 | mm = get_task_mm(task); 88 | 89 | if (!mm) { return res; } 90 | 91 | down_read(&mm->MM_STRUCT_MMAP_LOCK); 92 | 93 | vma = find_vma(mm, proc_virt_addr); 94 | if (vma) { 95 | if (vma->vm_flags & VM_WRITE) { 96 | size_t read_end = proc_virt_addr + size; 97 | if (read_end <= vma->vm_end) { 98 | res = 1; 99 | } 100 | } 101 | } 102 | up_read(&mm->MM_STRUCT_MMAP_LOCK); 103 | mmput(mm); 104 | return res; 105 | } 106 | 107 | /* 108 | * Indicate if the VMA is a stack for the given task; for 109 | * /proc/PID/maps that is the stack of the main task. 110 | */ 111 | static int is_stack(struct vm_area_struct *vma) { 112 | /* 113 | * We make no effort to guess what a given thread considers to be 114 | * its "stack". It's not even well-defined for programs written 115 | * languages like Go. 116 | */ 117 | return vma->vm_start <= vma->vm_mm->start_stack && 118 | vma->vm_end >= vma->vm_mm->start_stack; 119 | } 120 | static int get_proc_maps_list(struct pid* proc_pid_struct, size_t max_path_length, char* lpBuf, size_t buf_size, bool is_kernel_buf, int* have_pass) { 121 | struct task_struct* task; 122 | struct mm_struct* mm; 123 | struct vm_area_struct* vma; 124 | char new_path[MY_PATH_MAX_LEN]; 125 | char path_buf[MY_PATH_MAX_LEN]; 126 | int success = 0; 127 | size_t copy_pos; 128 | size_t end_pos; 129 | 130 | 131 | if (max_path_length <= 0) { 132 | return -1; 133 | } 134 | 135 | task = pid_task(proc_pid_struct, PIDTYPE_PID); 136 | if (!task) { 137 | return -2; 138 | } 139 | 140 | mm = get_task_mm(task); 141 | 142 | if (!mm) { 143 | return -3; 144 | } 145 | if (is_kernel_buf) { 146 | memset(lpBuf, 0, buf_size); 147 | } 148 | //else if (clear_user(lpBuf, buf_size)) { return -4; } //清空用户的缓冲区 149 | 150 | copy_pos = (size_t)lpBuf; 151 | end_pos = (size_t)((size_t)lpBuf + buf_size); 152 | 153 | down_read(&mm->MM_STRUCT_MMAP_LOCK); 154 | for (vma = mm->mmap; vma; vma = vma->vm_next) { 155 | unsigned long start, end; 156 | unsigned char flags[4]; 157 | struct file* vm_file; 158 | if (copy_pos >= end_pos) { 159 | if (have_pass) { 160 | *have_pass = 1; 161 | } 162 | break; 163 | } 164 | start = vma->vm_start; 165 | end = vma->vm_end; 166 | 167 | 168 | 169 | flags[0] = vma->vm_flags & VM_READ ? '\x01' : '\x00'; 170 | flags[1] = vma->vm_flags & VM_WRITE ? '\x01' : '\x00'; 171 | flags[2] = vma->vm_flags & VM_EXEC ? '\x01' : '\x00'; 172 | flags[3] = vma->vm_flags & VM_MAYSHARE ? '\x01' : '\x00'; 173 | 174 | 175 | memset(new_path, 0, sizeof(new_path)); 176 | vm_file = vma->vm_file; 177 | if (vm_file) { 178 | char* path; 179 | memset(path_buf, 0, sizeof(path_buf)); 180 | path = d_path(&vm_file->f_path, path_buf, sizeof(path_buf)); 181 | if (path > 0) { 182 | strncat(new_path, path, sizeof(new_path) - 1); 183 | } 184 | } else if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) { 185 | if ((sizeof(new_path) - strlen(new_path) - 7) >= 0) { 186 | strcat(new_path, "[vdso]"); 187 | } 188 | } else { 189 | if (vma->vm_start <= mm->brk && 190 | vma->vm_end >= mm->start_brk) { 191 | if ((sizeof(new_path) - strlen(new_path) - 7) >= 0) { 192 | strcat(new_path, "[heap]"); 193 | } 194 | } else { 195 | if (is_stack(vma)) { 196 | /* 197 | * Thread stack in /proc/PID/task/TID/maps or 198 | * the main process stack. 199 | */ 200 | 201 | /* Thread stack in /proc/PID/maps */ 202 | if ((sizeof(new_path) - strlen(new_path) - 8) >= 0) { 203 | strcat(new_path, "[stack]"); 204 | } 205 | } 206 | 207 | } 208 | 209 | } 210 | if (is_kernel_buf) { 211 | memcpy((void*)copy_pos, &start, 8); 212 | copy_pos += 8; 213 | memcpy((void*)copy_pos, &end, 8); 214 | copy_pos += 8; 215 | memcpy((void*)copy_pos, &flags, 4); 216 | copy_pos += 4; 217 | memcpy((void*)copy_pos, &new_path, max_path_length > MY_PATH_MAX_LEN ? MY_PATH_MAX_LEN : max_path_length - 1); 218 | copy_pos += max_path_length; 219 | } else { 220 | //内核空间->用户空间交换数据 221 | if (!!x_copy_to_user((void*)copy_pos, &start, 8)) { 222 | if (have_pass) { 223 | *have_pass = 1; 224 | } 225 | break; 226 | } 227 | copy_pos += 8; 228 | 229 | if (!!x_copy_to_user((void*)copy_pos, &end, 8)) { 230 | if (have_pass) { 231 | *have_pass = 1; 232 | } 233 | break; 234 | } 235 | copy_pos += 8; 236 | 237 | if (!!x_copy_to_user((void*)copy_pos, &flags, 4)) { 238 | if (have_pass) { 239 | *have_pass = 1; 240 | } 241 | break; 242 | } 243 | copy_pos += 4; 244 | 245 | if (!!x_copy_to_user((void*)copy_pos, &new_path, max_path_length > MY_PATH_MAX_LEN ? MY_PATH_MAX_LEN : max_path_length - 1)) { 246 | if (have_pass) { 247 | *have_pass = 1; 248 | } 249 | break; 250 | } 251 | copy_pos += max_path_length; 252 | 253 | } 254 | success++; 255 | } 256 | up_read(&mm->MM_STRUCT_MMAP_LOCK); 257 | mmput(mm); 258 | 259 | return success; 260 | } 261 | 262 | #endif /* PROC_MAPS_H_ */ -------------------------------------------------------------------------------- /rwMem/bp.c: -------------------------------------------------------------------------------- 1 | #include "bp.h" 2 | #include "api_proxy.h" 3 | #include "asm/current.h" 4 | #include "asm/debug-monitors.h" 5 | #include "asm/processor.h" 6 | #include "asm/ptrace.h" 7 | #include "linux/anon_inodes.h" 8 | #include "linux/atomic/atomic-instrumented.h" 9 | #include "linux/file.h" 10 | #include "linux/hw_breakpoint.h" 11 | #include "linux/poll.h" 12 | #include "linux/spinlock.h" 13 | #include "linux/spinlock_types.h" 14 | #include "linux/task_work.h" 15 | #include "linux/types.h" 16 | #include "linux/wait.h" 17 | 18 | struct hit_bp_cb { 19 | struct callback_head twork; 20 | struct file *file; 21 | }; 22 | 23 | DEFINE_SPINLOCK(step_list_lock); 24 | LIST_HEAD(step_list); 25 | 26 | struct step_list_entry { 27 | struct list_head list; 28 | pid_t pid; 29 | struct file *file; 30 | bool removed; 31 | }; 32 | 33 | static void bp_callback_after(struct callback_head *twork) 34 | { 35 | struct hit_bp_cb *twcb = container_of(twork, struct hit_bp_cb, twork); 36 | struct rwmem_bp_private_data *priv_data = twcb->file->private_data; 37 | 38 | // mark stopped 39 | spin_lock(&priv_data->flag_lock); 40 | priv_data->stopped_flag = true; 41 | spin_unlock(&priv_data->flag_lock); 42 | 43 | // wake up the fasync 44 | kill_fasync(&priv_data->fasync, SIGIO, POLL_IN); 45 | 46 | // wake up the poll 47 | atomic_set(&priv_data->poll, EPOLLIN); 48 | wake_up_all(&priv_data->poll_wq); 49 | 50 | // wait for continue 51 | wait_event(priv_data->wq, priv_data->continue_flag); 52 | 53 | // we can continue here, unset flags 54 | atomic_set(&priv_data->poll, 0); 55 | spin_lock(&priv_data->flag_lock); 56 | priv_data->continue_flag = false; 57 | priv_data->stopped_flag = false; 58 | spin_unlock(&priv_data->flag_lock); 59 | 60 | // clean up 61 | kfree(twcb); 62 | } 63 | 64 | int rwmem_bp_step_handler(struct pt_regs *regs, unsigned long esr) 65 | { 66 | pid_t pid = current->pid; 67 | struct hit_bp_cb *twcb; 68 | struct list_head *pos; 69 | struct step_list_entry *entry; 70 | struct file *file = NULL; 71 | bool removed; 72 | 73 | // Find the file associated with the pid 74 | spin_lock(&step_list_lock); 75 | list_for_each (pos, &step_list) { 76 | entry = list_entry(pos, struct step_list_entry, list); 77 | if (entry->pid == pid) { 78 | file = entry->file; 79 | removed = entry->removed; 80 | list_del(pos); 81 | kfree(entry); 82 | // if the file is closed, just ignore it 83 | if (removed) { 84 | printk(KERN_INFO 85 | "step_callback find a removed step\n"); 86 | spin_unlock(&step_list_lock); 87 | return DBG_HOOK_HANDLED; 88 | } 89 | break; 90 | } 91 | } 92 | spin_unlock(&step_list_lock); 93 | 94 | // If no file is found, we cannot continue 95 | if (!file) { 96 | return DBG_HOOK_ERROR; 97 | } 98 | 99 | // create a resume task 100 | printk(KERN_INFO "step_callback %lx\n", regs->pc); 101 | twcb = kzalloc(sizeof(*twcb), GFP_KERNEL); 102 | twcb->file = file; 103 | init_task_work(&twcb->twork, bp_callback_after); 104 | task_work_add(current, &twcb->twork, TWA_RESUME); 105 | 106 | // remove the single step flag 107 | user_disable_single_step(current); 108 | return DBG_HOOK_HANDLED; 109 | } 110 | 111 | void bp_callback(struct perf_event *perf, struct perf_sample_data *sample_data, 112 | struct pt_regs *regs) 113 | { 114 | struct hit_bp_cb *twcb; 115 | struct file *file = 116 | (void *)((uint64_t)(perf->overflow_handler_context) | 117 | ((uint64_t)0xff << 56)); 118 | struct debug_info *debug_info; 119 | debug_info = ¤t->thread.debug; 120 | 121 | printk(KERN_INFO "bp_callback %lx\n", regs->pc); 122 | 123 | // create a resume task 124 | twcb = kzalloc(sizeof(*twcb), GFP_KERNEL); 125 | twcb->file = file; 126 | init_task_work(&twcb->twork, bp_callback_after); 127 | task_work_add(current, &twcb->twork, TWA_RESUME); 128 | } 129 | 130 | static int rwmem_bp_fasync(int fd, struct file *filp, int on) 131 | { 132 | struct inode *inode = file_inode(filp); 133 | struct rwmem_bp_private_data *event = filp->private_data; 134 | int retval; 135 | 136 | inode_lock(inode); 137 | retval = fasync_helper(fd, filp, on, &event->fasync); 138 | inode_unlock(inode); 139 | 140 | if (retval < 0) 141 | return retval; 142 | 143 | return 0; 144 | } 145 | 146 | static __poll_t rwmem_bp_poll(struct file *file, poll_table *wait) 147 | { 148 | struct rwmem_bp_private_data *event = file->private_data; 149 | __poll_t events; 150 | poll_wait(file, &event->poll_wq, wait); 151 | events = atomic_xchg(&event->poll, 0); 152 | return events; 153 | } 154 | 155 | int rwmem_bp_release(struct inode *inode, struct file *filp) 156 | { 157 | struct step_list_entry *entry; 158 | struct rwmem_bp_private_data *data = filp->private_data; 159 | // wake up target task 160 | spin_lock(&data->flag_lock); 161 | data->continue_flag = true; 162 | spin_unlock(&data->flag_lock); 163 | wake_up_all(&data->wq); 164 | 165 | // mark the file as removed 166 | spin_lock(&step_list_lock); 167 | list_for_each_entry (entry, &step_list, list) { 168 | if (entry->file == filp) { 169 | entry->removed = true; 170 | break; 171 | } 172 | } 173 | spin_unlock(&step_list_lock); 174 | 175 | // clean up 176 | if (data->event) { 177 | unregister_hw_breakpoint(data->event); 178 | } 179 | if (data->target_task) { 180 | put_task_struct(data->target_task); 181 | } 182 | 183 | kfree(data); 184 | filp->private_data = NULL; 185 | return 0; 186 | } 187 | ssize_t rwmem_bp_read(struct file *filp, char __user *buf, size_t size, 188 | loff_t *ppos) 189 | { 190 | struct rwmem_bp_private_data *data = filp->private_data; 191 | struct user_fpsimd_state *uregs; 192 | struct pt_regs *pt_regs; 193 | 194 | // If the target task is not stopped, we cannot read the registers 195 | if (!data->stopped_flag) { 196 | return -EINVAL; 197 | } 198 | pt_regs = task_pt_regs(data->target_task); 199 | 200 | if (sizeof(pt_regs->user_regs) + sizeof(*uregs) <= size) { 201 | // The buffer is large enough. Copy both pt_regs and uregs 202 | uregs = &data->target_task->thread.uw.fpsimd_state; 203 | if (x_copy_to_user(buf, &pt_regs->user_regs, 204 | sizeof(pt_regs->user_regs))) { 205 | return -EFAULT; 206 | } 207 | if (x_copy_to_user(buf + sizeof(pt_regs->user_regs), uregs, 208 | sizeof(*uregs))) { 209 | return -EFAULT; 210 | } 211 | return sizeof(*pt_regs) + sizeof(*uregs); 212 | } else if (sizeof(pt_regs->user_regs) <= size) { 213 | // The buffer is large enough for pt_regs only 214 | if (x_copy_to_user(buf, &pt_regs->user_regs, 215 | sizeof(pt_regs->user_regs))) { 216 | return -EFAULT; 217 | } 218 | return sizeof(*pt_regs); 219 | } else { 220 | // The buffer is too small 221 | return -EINVAL; 222 | } 223 | } 224 | long rwmem_bp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 225 | { 226 | switch (cmd) { 227 | case IOCTL_BP_CONTINUE: { 228 | struct rwmem_bp_private_data *data = filp->private_data; 229 | // If the target task is not stopped, we cannot continue 230 | if (!data->stopped_flag) { 231 | return -EINVAL; 232 | } 233 | spin_lock(&data->flag_lock); 234 | data->continue_flag = true; 235 | spin_unlock(&data->flag_lock); 236 | wake_up(&data->wq); 237 | return 0; 238 | } 239 | case IOCTL_BP_SET_REG: { 240 | struct set_reg_param param; 241 | struct rwmem_bp_private_data *data = filp->private_data; 242 | struct pt_regs *pt_regs; 243 | if (!data->stopped_flag) { 244 | return -EINVAL; 245 | } 246 | if (x_copy_from_user((void *)¶m, (void *)arg, 247 | sizeof(param))) { 248 | return -EFAULT; 249 | } 250 | if (param.id >= 34) { 251 | return -EINVAL; 252 | } 253 | pt_regs = task_pt_regs(data->target_task); 254 | pt_regs->user_regs.regs[param.id] = param.value; 255 | return 0; 256 | } 257 | case IOCTL_BP_SET_SIMD_REG: { 258 | struct rwmem_bp_private_data *data = filp->private_data; 259 | struct user_fpsimd_state *uregs = 260 | &data->target_task->thread.uw.fpsimd_state; 261 | struct set_simd_reg_param param; 262 | if (!data->stopped_flag) { 263 | return -EINVAL; 264 | } 265 | if (x_copy_from_user((void *)¶m, (void *)arg, 266 | sizeof(param))) { 267 | return -EFAULT; 268 | } 269 | if (param.id < 32) { 270 | uregs->vregs[param.id] = param.value; 271 | return 0; 272 | } else if (param.id == 32) { 273 | uregs->fpsr = param.value; 274 | return 0; 275 | } else if (param.id == 33) { 276 | uregs->fpcr = param.value; 277 | return 0; 278 | } else { 279 | return -EINVAL; 280 | } 281 | } 282 | case IOCTL_BP_STEP: { 283 | struct debug_info *debug_info; 284 | struct step_list_entry *entry; 285 | struct rwmem_bp_private_data *data = filp->private_data; 286 | 287 | // If the target task is not stopped, we cannot continue 288 | if (!data->stopped_flag) { 289 | return -EINVAL; 290 | } 291 | // Add the pid to the step list 292 | spin_lock(&step_list_lock); 293 | entry = (struct step_list_entry *)kmalloc( 294 | sizeof(struct step_list_entry), GFP_KERNEL); 295 | entry->pid = data->target_task->pid; 296 | entry->file = filp; 297 | entry->removed = false; 298 | list_add(&entry->list, &step_list); 299 | spin_unlock(&step_list_lock); 300 | 301 | // Set the single step flag 302 | debug_info = &data->target_task->thread.debug; 303 | // FIXME: check whether the target task is already in single step mode (for example ptrace) 304 | // Currently, we just consider whether it is in step mode by hw_breakpoint. 305 | if (test_ti_thread_flag(&data->target_task->thread_info, 306 | TIF_SINGLESTEP)) 307 | debug_info->suspended_step = 1; 308 | else 309 | user_enable_single_step(data->target_task); 310 | 311 | // Wake up the target task 312 | spin_lock(&data->flag_lock); 313 | data->continue_flag = true; 314 | spin_unlock(&data->flag_lock); 315 | wake_up(&data->wq); 316 | return 0; 317 | } 318 | case IOCTL_BP_IS_STOPPED: { 319 | struct rwmem_bp_private_data *data = filp->private_data; 320 | return !!data->stopped_flag; 321 | } 322 | default: 323 | return -EINVAL; 324 | } 325 | } 326 | 327 | static const struct file_operations rwmem_bp_fops = { 328 | .owner = THIS_MODULE, 329 | 330 | .llseek = no_llseek, 331 | .poll = rwmem_bp_poll, 332 | .read = rwmem_bp_read, 333 | .unlocked_ioctl = rwmem_bp_ioctl, 334 | .release = rwmem_bp_release, 335 | .fasync = rwmem_bp_fasync, 336 | }; 337 | 338 | struct file *create_rwmem_bp_file(void) 339 | { 340 | struct rwmem_bp_private_data *data = 341 | kzalloc(sizeof(struct rwmem_bp_private_data), GFP_KERNEL); 342 | init_waitqueue_head(&data->wq); 343 | init_waitqueue_head(&data->poll_wq); 344 | spin_lock_init(&data->flag_lock); 345 | return anon_inode_getfile("[bp_handle]", &rwmem_bp_fops, data, O_RDWR); 346 | } -------------------------------------------------------------------------------- /rwMem/phy_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef PHY_MEM_H_ 2 | #define PHY_MEM_H_ 3 | // 声明 4 | ////////////////////////////////////////////////////////////////////////// 5 | #include "api_proxy.h" 6 | #include "asm-generic/bitops/const_hweight.h" 7 | #include "linux/mm.h" 8 | #include "ver_control.h" 9 | #include 10 | #include 11 | #include 12 | 13 | static inline int is_pte_can_read(pte_t *pte); 14 | static inline int is_pte_can_write(pte_t *pte); 15 | static inline int is_pte_can_exec(pte_t *pte); 16 | static inline int change_pte_read_status(pte_t *pte, bool can_read); 17 | static inline int change_pte_write_status(pte_t *pte, bool can_write); 18 | static inline int change_pte_exec_status(pte_t *pte, bool can_exec); 19 | 20 | static inline size_t get_task_proc_phy_addr(struct task_struct *task, 21 | size_t virt_addr, pte_t *out_pte); 22 | static inline size_t get_proc_phy_addr(struct pid *proc_pid_struct, 23 | size_t virt_addr, pte_t *out_pte); 24 | static inline size_t read_ram_physical_addr(size_t phy_addr, char *lpBuf, 25 | bool is_kernel_buf, 26 | size_t read_size); 27 | static inline size_t write_ram_physical_addr(size_t phy_addr, char *lpBuf, 28 | bool is_kernel_buf, 29 | size_t write_size); 30 | 31 | // 实现 32 | ////////////////////////////////////////////////////////////////////////// 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 83) 39 | #include 40 | #include 41 | 42 | #endif 43 | 44 | #define RETURN_VALUE(size_t_ptr___out_ret, size_t___value) \ 45 | *size_t_ptr___out_ret = size_t___value; \ 46 | break; 47 | 48 | #include 49 | 50 | static inline size_t get_task_proc_phy_addr(struct task_struct *task, 51 | size_t virt_addr, pte_t *out_pte) 52 | { 53 | struct mm_struct *mm; 54 | ////////////////////////////////////////////////////////////////////////// 55 | pgd_t *pgd; 56 | p4d_t *p4d; 57 | pud_t *pud; 58 | pmd_t *pmd; 59 | pte_t *pte; 60 | unsigned long paddr = 0; 61 | unsigned long page_addr = 0; 62 | unsigned long page_offset = 0; 63 | ////////////////////////////////////////////////////////////////////////// 64 | *(size_t *)out_pte = 0; 65 | 66 | if (!task) { 67 | return 0; 68 | } 69 | mm = get_task_mm(task); 70 | if (!mm) { 71 | return 0; 72 | } 73 | 74 | pgd = pgd_offset(mm, virt_addr); 75 | if (pgd == NULL) { 76 | printk_debug("pgd is null\n"); 77 | goto out; 78 | } 79 | printk_debug("pgd_val = 0x%lx pgd addr:0x%lx\n", 80 | (unsigned long int)pgd_val(*pgd), 81 | (unsigned long int)pgd_val(*pgd)); 82 | printk_debug("init_mm pgd val:0x%lx,pgd addr:0x%lx\n", 83 | (unsigned long)pgd_val(*(mm->pgd)), pgd_val(*(mm->pgd))); 84 | printk_debug("pgd_index = %d\n", pgd_index(virt_addr)); 85 | if (pgd_none(*pgd)) { 86 | printk_debug("not mapped in pgd\n"); 87 | goto out; 88 | } 89 | printk_debug("pgd_offset ok\n"); 90 | 91 | /* 92 | * (p4ds are folded into pgds so this doesn't get actually called, 93 | * but the define is needed for a generic inline function.) 94 | */ 95 | p4d = p4d_offset(pgd, virt_addr); 96 | // printk_debug("p4d_val = 0x%lx, p4d_index = %lu\n", p4d_val(*p4d), p4d_index(virt_addr)); 97 | printk_debug("p4d_val = 0x%lx\n", p4d_val(*p4d)); 98 | if (p4d_none(*p4d)) { 99 | printk_debug("not mapped in p4d\n"); 100 | goto out; 101 | } 102 | 103 | pud = pud_offset(p4d, virt_addr); 104 | printk_debug("pud_val = 0x%llx \n", pud_val(*pud)); 105 | if (pud_none(*pud)) { 106 | printk_debug("not mapped in pud\n"); 107 | goto out; 108 | } 109 | printk_debug("pud_offset ok\n"); 110 | 111 | pmd = pmd_offset(pud, virt_addr); 112 | printk_debug("pmd_val = 0x%llx\n", pmd_val(*pmd)); 113 | // printk_debug("pmd_index = %d\n", pmd_index(virt_addr)); 114 | if (pmd_none(*pmd)) { 115 | printk_debug("not mapped in pmd\n"); 116 | goto out; 117 | } 118 | printk_debug("pmd_offset ok\n"); 119 | 120 | pte = pte_offset_kernel(pmd, virt_addr); 121 | printk_debug("pte_val = 0x%llx\n", pte_val(*pte)); 122 | // printk_debug("pte_index = %d\n", pte_index(virt_addr)); 123 | if (pte_none(*pte)) { 124 | printk_debug("not mapped in pte\n"); 125 | goto out; 126 | } 127 | printk_debug("pte_offset_kernel ok\n"); 128 | 129 | page_addr = page_to_phys(pte_page(*pte)); 130 | 131 | page_offset = virt_addr & ~PAGE_MASK; 132 | paddr = page_addr | page_offset; 133 | 134 | printk_debug("page_addr = %llx, page_offset = %llx\n", page_addr, 135 | page_offset); 136 | printk_debug("vaddr = %llx, paddr = %llx\n", virt_addr, paddr); 137 | 138 | *(size_t *)out_pte = (size_t)pte; 139 | 140 | out: 141 | mmput(mm); 142 | return paddr; 143 | } 144 | 145 | static inline size_t get_proc_phy_addr(struct pid *proc_pid_struct, 146 | size_t virt_addr, pte_t *out_pte) 147 | { 148 | struct task_struct *task = pid_task(proc_pid_struct, PIDTYPE_PID); 149 | if (!task) { 150 | return 0; 151 | } 152 | return get_task_proc_phy_addr(task, virt_addr, out_pte); 153 | } 154 | 155 | static inline int is_pte_can_read(pte_t *pte) 156 | { 157 | if (!pte) { 158 | return 0; 159 | } 160 | #ifdef pte_read 161 | return pte_read(*pte); 162 | #endif 163 | return 1; 164 | } 165 | static inline int is_pte_can_write(pte_t *pte) 166 | { 167 | return pte && pte_write(*pte); 168 | } 169 | static inline int is_pte_can_exec(pte_t *pte) 170 | { 171 | if (!pte) { 172 | return 0; 173 | } 174 | #ifdef pte_exec 175 | return pte_exec(*pte); 176 | #endif 177 | #ifdef pte_user_exec 178 | return (pte_user_exec(*pte)); 179 | #endif 180 | return 0; 181 | } 182 | static inline int change_pte_read_status(pte_t *pte, bool can_read) 183 | { 184 | return !!pte; 185 | } 186 | static inline int change_pte_write_status(pte_t *pte, bool can_write) 187 | { 188 | if (!pte) { 189 | return 0; 190 | } 191 | if (can_write) { 192 | // ARM64:删除内存“仅可读”属性,此时内存内存可读、可写 193 | set_pte(pte, pte_mkwrite(*pte)); 194 | } else { 195 | // ARM64:设置内存“仅可读”属性,此时内存内存可读、不可写 196 | set_pte(pte, pte_wrprotect(*pte)); 197 | } 198 | return 1; 199 | } 200 | static inline int change_pte_exec_status(pte_t *pte, bool can_exec) 201 | { 202 | if (!pte) { 203 | return 0; 204 | } 205 | if (can_exec) { 206 | #ifdef pte_mknexec 207 | set_pte(pte, pte_mknexec(*pte)); 208 | #endif 209 | } else { 210 | #ifdef pte_mkexec 211 | set_pte(pte, pte_mkexec(*pte)); 212 | #endif 213 | } 214 | return 1; 215 | } 216 | 217 | static inline unsigned long size_inside_page(unsigned long start, 218 | unsigned long size) 219 | { 220 | unsigned long sz; 221 | 222 | sz = PAGE_SIZE - (start & (PAGE_SIZE - 1)); 223 | 224 | return min(sz, size); 225 | } 226 | 227 | static inline int check_phys_addr_valid_range(size_t addr, size_t count) 228 | { 229 | static size_t g_phy_total_memory_size = 0; 230 | if (g_phy_total_memory_size == 0) { 231 | struct sysinfo si; 232 | unsigned int bitcount = 0; 233 | si_meminfo(&si); 234 | bitcount = hweight32(si.mem_unit-1)+1; 235 | si.totalram <<= bitcount; 236 | g_phy_total_memory_size = __pa(si.totalram); 237 | } 238 | return (addr + count) <= g_phy_total_memory_size; 239 | } 240 | 241 | static inline size_t read_ram_physical_addr(size_t phy_addr, char *lpBuf, 242 | bool is_kernel_buf, 243 | size_t read_size) 244 | { 245 | void *bounce; 246 | size_t realRead = 0; 247 | if (!check_phys_addr_valid_range(phy_addr, read_size)) { 248 | printk_debug( 249 | KERN_INFO 250 | "Error in check_phys_addr_valid_range:%p,size:%zu\n", 251 | phy_addr, read_size); 252 | return 0; 253 | } 254 | bounce = kmalloc(PAGE_SIZE, GFP_KERNEL); 255 | if (!bounce) { 256 | return 0; 257 | } 258 | 259 | while (read_size > 0) { 260 | size_t sz = size_inside_page(phy_addr, read_size); 261 | 262 | /* 263 | * On ia64 if a page has been mapped somewhere as uncached, then 264 | * it must also be accessed uncached by the kernel or data 265 | * corruption may occur. 266 | */ 267 | 268 | char *ptr = xlate_dev_mem_ptr(phy_addr); 269 | int probe; 270 | 271 | if (!ptr) { 272 | printk_debug(KERN_INFO 273 | "Error in x_xlate_dev_mem_ptr:0x%llx\n", 274 | phy_addr); 275 | break; 276 | } 277 | probe = x_probe_kernel_read(bounce, ptr, sz); 278 | unxlate_dev_mem_ptr(phy_addr, ptr); 279 | if (probe) { 280 | break; 281 | } 282 | if (is_kernel_buf) { 283 | memcpy(lpBuf, bounce, sz); 284 | } else { 285 | unsigned long remaining = 286 | x_copy_to_user(lpBuf, bounce, sz); 287 | if (remaining) { 288 | printk_debug(KERN_INFO 289 | "Error in x_copy_to_user\n"); 290 | break; 291 | } 292 | } 293 | lpBuf += sz; 294 | phy_addr += sz; 295 | read_size -= sz; 296 | realRead += sz; 297 | } 298 | kfree(bounce); 299 | return realRead; 300 | } 301 | 302 | static inline size_t write_ram_physical_addr(size_t phy_addr, char *lpBuf, 303 | bool is_kernel_buf, 304 | size_t write_size) 305 | { 306 | size_t realWrite = 0; 307 | if (!check_phys_addr_valid_range(phy_addr, write_size)) { 308 | printk_debug( 309 | KERN_INFO 310 | "Error in check_phys_addr_valid_range:0x%llx,size:%zu\n", 311 | phy_addr, write_size); 312 | return 0; 313 | } 314 | 315 | while (write_size > 0) { 316 | size_t sz = size_inside_page(phy_addr, write_size); 317 | 318 | /* 319 | * On ia64 if a page has been mapped somewhere as uncached, then 320 | * it must also be accessed uncached by the kernel or data 321 | * corruption may occur. 322 | */ 323 | 324 | char *ptr = xlate_dev_mem_ptr(phy_addr); 325 | if (!ptr) { 326 | printk_debug(KERN_INFO 327 | "Error in xlate_dev_mem_ptr:0x%llx\n", 328 | phy_addr); 329 | break; 330 | } 331 | if (is_kernel_buf) { 332 | memcpy(ptr, lpBuf, sz); 333 | } else { 334 | unsigned long copied = x_copy_from_user(ptr, lpBuf, sz); 335 | if (copied) { 336 | unxlate_dev_mem_ptr(phy_addr, ptr); 337 | realWrite += sz - copied; 338 | printk_debug(KERN_INFO 339 | "Error in x_copy_from_user\n"); 340 | break; 341 | } 342 | } 343 | unxlate_dev_mem_ptr(phy_addr, ptr); 344 | 345 | lpBuf += sz; 346 | phy_addr += sz; 347 | write_size -= sz; 348 | realWrite += sz; 349 | } 350 | return realWrite; 351 | } 352 | 353 | // Update - RW party: drivers/char/mem.c 354 | 355 | #endif /* PHY_MEM_H_ */ -------------------------------------------------------------------------------- /rwMem/sys.c: -------------------------------------------------------------------------------- 1 | #include "sys.h" 2 | #include "api_proxy.h" 3 | #include "asm/debug-monitors.h" 4 | #include "bp.h" 5 | #include "linux/fdtable.h" 6 | #include "linux/file.h" 7 | #include "linux/hw_breakpoint.h" 8 | #include "linux/kern_levels.h" 9 | #include "linux/pid.h" 10 | #include "linux/printk.h" 11 | #include "linux/slab.h" 12 | #include "linux/types.h" 13 | #include "linux/wait.h" 14 | #include "phy_mem.h" 15 | #include "proc_maps.h" 16 | 17 | int rwmem_open(struct inode *inode, struct file *filp) 18 | { 19 | return 0; 20 | } 21 | 22 | int rwmem_release(struct inode *inode, struct file *filp) 23 | { 24 | return 0; 25 | } 26 | 27 | ssize_t rwmem_read(struct file *filp, char __user *buf, size_t size, 28 | loff_t *ppos) 29 | { 30 | char data[17] = { 0 }; 31 | unsigned long read = x_copy_from_user(data, buf, 17); 32 | if (read == 0) { 33 | pid_t pid = (pid_t) * (size_t *)&data; 34 | size_t proc_virt_addr = *(size_t *)&data[8]; 35 | bool is_force_read = data[16] == '\x01' ? true : false; 36 | size_t read_size = 0; 37 | struct pid *pid_struct = find_get_pid(pid); 38 | if (!pid_struct) { 39 | return -EINVAL; 40 | } 41 | 42 | if (is_force_read == false && 43 | !check_proc_map_can_read(pid_struct, proc_virt_addr, 44 | size)) { 45 | put_pid(pid_struct); 46 | return -EFAULT; 47 | } 48 | 49 | while (read_size < size) { 50 | size_t phy_addr = 0; 51 | size_t pfn_sz = 0; 52 | char *lpOutBuf = NULL; 53 | 54 | pte_t *pte; 55 | 56 | bool old_pte_can_read; 57 | phy_addr = get_proc_phy_addr(pid_struct, 58 | proc_virt_addr + read_size, 59 | (pte_t *)&pte); 60 | printk_debug(KERN_INFO "calc phy_addr:0x%zx\n", 61 | phy_addr); 62 | if (phy_addr == 0) { 63 | break; 64 | } 65 | 66 | old_pte_can_read = is_pte_can_read(pte); 67 | if (is_force_read) { 68 | if (!old_pte_can_read) { 69 | if (!change_pte_read_status(pte, 70 | true)) { 71 | break; 72 | } 73 | } 74 | } else if (!old_pte_can_read) { 75 | break; 76 | } 77 | 78 | pfn_sz = size_inside_page( 79 | phy_addr, ((size - read_size) > PAGE_SIZE) ? 80 | PAGE_SIZE : 81 | (size - read_size)); 82 | printk_debug(KERN_INFO "pfn_sz:%zu\n", pfn_sz); 83 | 84 | lpOutBuf = (char *)(buf + read_size); 85 | read_ram_physical_addr(phy_addr, lpOutBuf, false, 86 | pfn_sz); 87 | 88 | if (is_force_read && old_pte_can_read == false) { 89 | change_pte_read_status(pte, false); 90 | } 91 | 92 | read_size += pfn_sz; 93 | } 94 | 95 | put_pid(pid_struct); 96 | return read_size; 97 | } else { 98 | printk_debug(KERN_INFO 99 | "READ FAILED ret:%lu, user:%p, size:%zu\n", 100 | read, buf, size); 101 | } 102 | return -EFAULT; 103 | } 104 | 105 | ssize_t rwmem_write(struct file *filp, const char __user *buf, size_t size, 106 | loff_t *ppos) 107 | { 108 | char data[17] = { 0 }; 109 | unsigned long write = x_copy_from_user(data, buf, 17); 110 | if (write == 0) { 111 | pid_t pid = (pid_t) * (size_t *)data; 112 | size_t proc_virt_addr = *(size_t *)&data[8]; 113 | bool is_force_write = data[16] == '\x01' ? true : false; 114 | size_t write_size = 0; 115 | struct pid *pid_struct = find_get_pid(pid); 116 | if (!pid_struct) { 117 | return -EINVAL; 118 | } 119 | 120 | if (is_force_write == false && 121 | !check_proc_map_can_write(pid_struct, proc_virt_addr, 122 | size)) { 123 | put_pid(pid_struct); 124 | return -EFAULT; 125 | } 126 | 127 | while (write_size < size) { 128 | size_t phy_addr = 0; 129 | size_t pfn_sz = 0; 130 | char *lpInputBuf = NULL; 131 | 132 | pte_t *pte; 133 | bool old_pte_can_write; 134 | phy_addr = 135 | get_proc_phy_addr(pid_struct, 136 | proc_virt_addr + write_size, 137 | (pte_t *)&pte); 138 | 139 | printk_debug(KERN_INFO "phy_addr:0x%zx\n", phy_addr); 140 | if (phy_addr == 0) { 141 | break; 142 | } 143 | 144 | old_pte_can_write = is_pte_can_write(pte); 145 | if (is_force_write) { 146 | if (!old_pte_can_write) { 147 | if (!change_pte_write_status(pte, 148 | true)) { 149 | break; 150 | } 151 | } 152 | } else if (!old_pte_can_write) { 153 | break; 154 | } 155 | 156 | pfn_sz = size_inside_page( 157 | phy_addr, ((size - write_size) > PAGE_SIZE) ? 158 | PAGE_SIZE : 159 | (size - write_size)); 160 | printk_debug(KERN_INFO "pfn_sz:%zu\n", pfn_sz); 161 | 162 | lpInputBuf = (char *)(((size_t)buf + (size_t)17 + 163 | write_size)); 164 | write_ram_physical_addr(phy_addr, lpInputBuf, false, 165 | pfn_sz); 166 | 167 | if (is_force_write && old_pte_can_write == false) { 168 | change_pte_write_status(pte, false); 169 | } 170 | 171 | write_size += pfn_sz; 172 | } 173 | put_pid(pid_struct); 174 | return write_size; 175 | } else { 176 | printk_debug(KERN_INFO 177 | "WRITE FAILED ret:%lu, user:%p, size:%zu\n", 178 | write, buf, size); 179 | } 180 | return -EFAULT; 181 | } 182 | 183 | long rwmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 184 | { 185 | switch (cmd) { 186 | case IOCTL_GET_PROCESS_MAPS_COUNT: { 187 | uint64_t res; 188 | struct pid *pid_struct; 189 | 190 | pid_struct = find_get_pid(arg); 191 | if (!pid_struct) { 192 | return -EINVAL; 193 | } 194 | res = get_proc_map_count(pid_struct); 195 | put_pid(pid_struct); 196 | 197 | return res; 198 | } 199 | case IOCTL_GET_PROCESS_MAPS_LIST: { 200 | char buf[24]; 201 | size_t name_len, buf_size; 202 | pid_t pid; 203 | struct pid *pid_struct; 204 | int have_pass = 0; 205 | uint64_t count = 0; 206 | if (x_copy_from_user((void *)buf, (void *)arg, 24)) { 207 | return -EINVAL; 208 | } 209 | pid = (pid_t) * (size_t *)buf; 210 | name_len = *(size_t *)&buf[8]; 211 | buf_size = *(size_t *)&buf[16]; 212 | 213 | pid_struct = find_get_pid(pid); 214 | if (!pid_struct) { 215 | return -EINVAL; 216 | } 217 | count = get_proc_maps_list(pid_struct, name_len, 218 | (void *)((size_t)arg + (size_t)8), 219 | buf_size - 8, false, &have_pass); 220 | put_pid(pid_struct); 221 | if (x_copy_to_user((void *)arg, &count, 8)) { 222 | return -EFAULT; 223 | } 224 | return have_pass; 225 | } 226 | case IOCTL_CHECK_PROCESS_ADDR_PHY: { 227 | struct { 228 | pid_t pid; 229 | size_t virt_addr_start, virt_addr_end; 230 | } param; 231 | size_t proc_virt_addr; 232 | struct pid *pid_struct; 233 | struct task_struct *task; 234 | pte_t *pte; 235 | size_t ret = 0; 236 | size_t pages, bufLen, i; 237 | uint8_t *retBuf; 238 | if (x_copy_from_user((void *)¶m, (void *)arg, 239 | sizeof(param))) { 240 | return -EFAULT; 241 | } 242 | if ((param.virt_addr_start | param.virt_addr_end) & 243 | (PAGE_SIZE - 1)) { 244 | return -EINVAL; 245 | } 246 | if (param.virt_addr_start >= param.virt_addr_end) { 247 | return -EINVAL; 248 | } 249 | 250 | pid_struct = find_get_pid(param.pid); 251 | if (!pid_struct) { 252 | return -EINVAL; 253 | } 254 | task = pid_task(pid_struct, PIDTYPE_PID); 255 | if (!task) { 256 | put_pid(pid_struct); 257 | return -EINVAL; 258 | } 259 | 260 | #define MAX_MALLOC_SIZE 1024 261 | 262 | pages = (param.virt_addr_end - param.virt_addr_start) / 263 | PAGE_SIZE; 264 | bufLen = (pages + 7) / 8; 265 | bufLen = bufLen > MAX_MALLOC_SIZE ? MAX_MALLOC_SIZE : bufLen; 266 | retBuf = kmalloc(bufLen, GFP_KERNEL); 267 | if (!retBuf) { 268 | put_pid(pid_struct); 269 | return -ENOMEM; 270 | } 271 | memset(retBuf, 0, bufLen); 272 | 273 | for (proc_virt_addr = param.virt_addr_start, i = 0; 274 | proc_virt_addr < param.virt_addr_end; 275 | proc_virt_addr += PAGE_SIZE) { 276 | ret = get_task_proc_phy_addr(task, proc_virt_addr, 277 | (pte_t *)&pte); 278 | if (ret && is_pte_can_read(pte)) { 279 | retBuf[i / 8] |= 1 << (i % 8); 280 | } 281 | i++; 282 | if (i == MAX_MALLOC_SIZE * 8) { 283 | if (x_copy_to_user((void *)arg, retBuf, 284 | bufLen)) { 285 | kfree(retBuf); 286 | put_pid(pid_struct); 287 | return -EFAULT; 288 | } 289 | i = 0; 290 | memset(retBuf, 0, bufLen); 291 | arg += MAX_MALLOC_SIZE; 292 | } 293 | } 294 | put_pid(pid_struct); 295 | if (i && x_copy_to_user((void *)arg, retBuf, (i + 7) / 8)) { 296 | kfree(retBuf); 297 | return -EFAULT; 298 | } 299 | kfree(retBuf); 300 | return pages; 301 | } 302 | case IOCTL_ADD_BP: { 303 | struct { 304 | pid_t pid; 305 | uint8_t type; 306 | uint8_t len; 307 | size_t virt_addr; 308 | } param; 309 | struct perf_event_attr attr; 310 | struct pid *pid_struct; 311 | struct task_struct *task; 312 | struct perf_event *bp; 313 | struct file *file; 314 | struct rwmem_bp_private_data * private_data; 315 | int fd; 316 | if (x_copy_from_user((void *)¶m, (void *)arg, 317 | sizeof(param))) { 318 | return -EFAULT; 319 | } 320 | if (param.type > 4) { 321 | return -EINVAL; 322 | } 323 | if (param.len != 1 && param.len != 2 && param.len != 4 && 324 | param.len != 8) { 325 | return -EINVAL; 326 | } 327 | 328 | pid_struct = find_get_pid(param.pid); 329 | if (!pid_struct) { 330 | return -EINVAL; 331 | } 332 | task = get_pid_task(pid_struct, PIDTYPE_PID); 333 | put_pid(pid_struct); 334 | if (!task) { 335 | return -EINVAL; 336 | } 337 | 338 | hw_breakpoint_init(&attr); 339 | attr.exclude_kernel = 1; 340 | attr.bp_addr = param.virt_addr; 341 | attr.bp_len = param.len; 342 | attr.bp_type = param.type; 343 | attr.disabled = 0; 344 | fd = get_unused_fd_flags(O_CLOEXEC); 345 | if (fd < 0) { 346 | put_task_struct(task); 347 | return fd; 348 | } 349 | file = create_rwmem_bp_file(); 350 | if (IS_ERR(file)) { 351 | put_task_struct(task); 352 | put_unused_fd(fd); 353 | return PTR_ERR(file); 354 | } 355 | fd_install(fd, file); 356 | 357 | bp = perf_event_create_kernel_counter( 358 | &attr, -1, task, bp_callback, 359 | (void *)(((uint64_t)file & ~((uint64_t)~((uint8_t)0xcb) << 56)))); 360 | if (IS_ERR(bp)) { 361 | put_task_struct(task); 362 | close_fd(fd); 363 | return PTR_ERR(bp); 364 | } 365 | private_data = file->private_data; 366 | private_data->event = bp; 367 | private_data->target_task = task; 368 | 369 | return fd; 370 | } 371 | case IOCTL_GET_NUM_BRPS: { 372 | return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; 373 | } 374 | case IOCTL_GET_NUM_WRPS: { 375 | return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; 376 | } 377 | default: 378 | return -EINVAL; 379 | } 380 | return -EINVAL; 381 | } 382 | 383 | static struct step_hook rwmem_bp_step_hook = { 384 | .fn = rwmem_bp_step_handler, 385 | }; 386 | 387 | 388 | static int __init rwmem_dev_init(void) 389 | { 390 | int result; 391 | printk(KERN_INFO "load %s\n", DEV_FILENAME); 392 | 393 | g_rwProcMem_devp = kmalloc(sizeof(struct rwmem_dev), GFP_KERNEL); 394 | if (!g_rwProcMem_devp) { 395 | result = -ENOMEM; 396 | goto _fail; 397 | } 398 | memset(g_rwProcMem_devp, 0, sizeof(struct rwmem_dev)); 399 | 400 | result = alloc_chrdev_region(&g_rwProcMem_devno, 0, 1, DEV_FILENAME); 401 | g_rwProcMem_major = MAJOR(g_rwProcMem_devno); 402 | 403 | if (result < 0) { 404 | printk(KERN_EMERG "rwProcMem alloc_chrdev_region failed %d\n", 405 | result); 406 | return result; 407 | } 408 | 409 | g_rwProcMem_devp->pcdev = kmalloc(sizeof(struct cdev) * 3, GFP_KERNEL); 410 | cdev_init(g_rwProcMem_devp->pcdev, 411 | (struct file_operations *)&rwmem_fops); 412 | g_rwProcMem_devp->pcdev->owner = THIS_MODULE; 413 | g_rwProcMem_devp->pcdev->ops = (struct file_operations *)&rwmem_fops; 414 | if (cdev_add(g_rwProcMem_devp->pcdev, g_rwProcMem_devno, 1)) { 415 | printk(KERN_NOTICE "Error in cdev_add()\n"); 416 | result = -EFAULT; 417 | goto _fail; 418 | } 419 | g_Class_devp = class_create(THIS_MODULE, DEV_FILENAME); 420 | device_create(g_Class_devp, NULL, g_rwProcMem_devno, NULL, "%s", 421 | DEV_FILENAME); 422 | register_user_step_hook(&rwmem_bp_step_hook); 423 | return 0; 424 | _fail: 425 | unregister_chrdev_region(g_rwProcMem_devno, 1); 426 | return result; 427 | } 428 | 429 | static void __exit rwmem_dev_exit(void) 430 | { 431 | device_destroy(g_Class_devp, g_rwProcMem_devno); 432 | class_destroy(g_Class_devp); 433 | 434 | cdev_del(g_rwProcMem_devp->pcdev); 435 | unregister_chrdev_region(g_rwProcMem_devno, 1); 436 | unregister_user_step_hook(&rwmem_bp_step_hook); 437 | kfree(g_rwProcMem_devp->pcdev); 438 | kfree(g_rwProcMem_devp); 439 | printk(KERN_INFO "unload %s\n", DEV_FILENAME); 440 | } 441 | 442 | module_init(rwmem_dev_init); 443 | module_exit(rwmem_dev_exit); 444 | 445 | MODULE_AUTHOR("Linux"); 446 | MODULE_DESCRIPTION("Linux default module"); 447 | MODULE_LICENSE("GPL"); 448 | -------------------------------------------------------------------------------- /librwmem/src/lib.rs: -------------------------------------------------------------------------------- 1 | use bitvec::{order::Lsb0, vec::BitVec}; 2 | use byteorder::{NativeEndian, ReadBytesExt}; 3 | use nix::{ioctl_none, ioctl_write_int, ioctl_write_ptr, request_code_readwrite}; 4 | use std::{ 5 | cmp::max, 6 | io::{Cursor, Read}, 7 | os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}, 8 | path::Path, 9 | }; 10 | 11 | pub mod errors; 12 | 13 | type Result = std::result::Result; 14 | 15 | const RWMEM_MAGIC: u8 = 100; 16 | const RWMEM_BP_MAGIC: u8 = 101; 17 | const IOCTL_GET_PROCESS_MAPS_COUNT: u8 = 0; 18 | const IOCTL_GET_PROCESS_MAPS_LIST: u8 = 1; 19 | const IOCTL_CHECK_PROCESS_ADDR_PHY: u8 = 2; 20 | 21 | #[derive(Debug, PartialEq, Eq)] 22 | pub struct MapsEntry { 23 | pub start: u64, 24 | pub end: u64, 25 | pub read_permission: bool, 26 | pub write_permission: bool, 27 | pub execute_permission: bool, 28 | pub shared: bool, 29 | pub name: String, 30 | } 31 | 32 | pub const DEFAULT_DRIVER_PATH: &str = "/dev/rwmem"; 33 | 34 | #[repr(transparent)] 35 | #[derive(Debug)] 36 | pub struct Device { 37 | fd: OwnedFd, 38 | } 39 | 40 | #[allow(dead_code)] 41 | impl Device { 42 | /// Create a new device. The default path is `DEFAULT_DRIVER_PATH`. 43 | pub fn new>(path: P) -> Result { 44 | let fd = nix::fcntl::open( 45 | path.as_ref(), 46 | nix::fcntl::OFlag::O_RDWR, 47 | nix::sys::stat::Mode::empty(), 48 | )?; 49 | Ok(Self { 50 | fd: unsafe { OwnedFd::from_raw_fd(fd) }, 51 | }) 52 | } 53 | 54 | pub fn from_raw_fd(fd: RawFd) -> Self { 55 | Self { 56 | fd: unsafe { OwnedFd::from_raw_fd(fd) }, 57 | } 58 | } 59 | pub fn as_raw_fd(&self) -> RawFd { 60 | self.fd.as_raw_fd() 61 | } 62 | /// read the memory of a process. 63 | pub fn read_mem(&self, pid: i32, addr: u64, buf: &mut [u8]) -> Result<()> { 64 | if buf.len() < 17 { 65 | let new_buf = &mut [0u8; 17]; 66 | new_buf[0..8].copy_from_slice(&(pid as i64).to_ne_bytes()); 67 | new_buf[8..16].copy_from_slice(&addr.to_ne_bytes()); 68 | let real_read = nix::errno::Errno::result(unsafe { 69 | libc::read( 70 | self.fd.as_raw_fd(), 71 | new_buf.as_mut_ptr() as *mut libc::c_void, 72 | buf.len(), 73 | ) 74 | })?; 75 | if real_read != buf.len() as isize { 76 | return Err(errors::Error::ReadFailed(buf.len(), real_read as usize)); 77 | } 78 | buf.copy_from_slice(&new_buf[..buf.len()]); 79 | } else { 80 | buf[0..8].copy_from_slice(&(pid as i64).to_ne_bytes()); 81 | buf[8..16].copy_from_slice(&addr.to_ne_bytes()); 82 | buf[17] = 0; 83 | let real_read = nix::errno::Errno::result(unsafe { 84 | libc::read( 85 | self.fd.as_raw_fd(), 86 | buf.as_mut_ptr() as *mut libc::c_void, 87 | buf.len(), 88 | ) 89 | })?; 90 | if real_read != buf.len() as isize { 91 | return Err(errors::Error::ReadFailed(buf.len(), real_read as usize)); 92 | } 93 | } 94 | Ok(()) 95 | } 96 | 97 | /// write the memory of a process. 98 | pub fn write_mem(&self, pid: i32, addr: u64, buf: &[u8]) -> Result<()> { 99 | let mut new_buf = vec![0u8; 17 + buf.len()]; 100 | new_buf[0..8].copy_from_slice(&(pid as i64).to_ne_bytes()); 101 | new_buf[8..16].copy_from_slice(&addr.to_ne_bytes()); 102 | new_buf[16] = 1; 103 | new_buf[17..].copy_from_slice(buf); 104 | let real_write = nix::errno::Errno::result(unsafe { 105 | libc::write( 106 | self.fd.as_raw_fd(), 107 | new_buf.as_ptr() as *const libc::c_void, 108 | buf.len(), 109 | ) 110 | })?; 111 | if real_write != buf.len() as isize { 112 | return Err(errors::Error::WriteFailed(buf.len(), real_write as usize)); 113 | } 114 | Ok(()) 115 | } 116 | 117 | /// get the memory map of a process. 118 | pub fn get_mem_map(&self, pid: i32, phy_only: bool) -> Result> { 119 | let count = self.get_mem_map_count(pid)?; 120 | let buf_len = 8 + (8 + 8 + 4 + 512) * (count + 50); 121 | let mut buf = vec![0u8; buf_len]; 122 | buf[0..8].copy_from_slice(&(pid as i64).to_ne_bytes()); 123 | buf[8..16].copy_from_slice(&512usize.to_ne_bytes()); 124 | buf[16..24].copy_from_slice(&buf_len.to_ne_bytes()); 125 | 126 | let unfinished = nix::errno::Errno::result(unsafe { 127 | libc::ioctl( 128 | self.fd.as_raw_fd(), 129 | request_code_readwrite!( 130 | RWMEM_MAGIC, 131 | IOCTL_GET_PROCESS_MAPS_LIST, 132 | std::mem::size_of::() 133 | ), 134 | buf.as_mut_ptr(), 135 | buf.len(), 136 | ) 137 | })?; 138 | if unfinished != 0 { 139 | return Err(errors::Error::MapsTooLong); 140 | } 141 | let mut cursor = Cursor::new(buf); 142 | let real_count = cursor.read_u64::()?; 143 | let mut result = Vec::with_capacity(real_count as usize); 144 | for _ in 0..real_count { 145 | let start = cursor.read_u64::()?; 146 | let end = cursor.read_u64::()?; 147 | let read_permission = cursor.read_u8()? != 0; 148 | let write_permission = cursor.read_u8()? != 0; 149 | let execute_permission = cursor.read_u8()? != 0; 150 | let shared = cursor.read_u8()? != 0; 151 | let mut name = [0u8; 512]; 152 | cursor.read_exact(&mut name)?; 153 | let mut name_length = 512usize; 154 | for (i, v) in name.iter().enumerate() { 155 | if *v == 0 { 156 | name_length = i; 157 | break; 158 | } 159 | } 160 | let name = String::from_utf8_lossy(&name[0..name_length]).to_string(); 161 | if phy_only { 162 | let is_mem_phy = self.is_mem_phy(pid, start, end)?; 163 | let mut is_last_phy = false; 164 | let mut begin_phy = 0u64; 165 | for (i, is_phy) in is_mem_phy.iter().enumerate() { 166 | if *is_phy { 167 | if !is_last_phy { 168 | begin_phy = start + i as u64 * 0x1000; 169 | is_last_phy = true; 170 | } 171 | } else if is_last_phy { 172 | let entry = MapsEntry { 173 | start: begin_phy, 174 | end: start + i as u64 * 0x1000, 175 | read_permission, 176 | write_permission, 177 | execute_permission, 178 | shared, 179 | name: name.clone(), 180 | }; 181 | is_last_phy = false; 182 | result.push(entry); 183 | } 184 | } 185 | if is_last_phy { 186 | let entry = MapsEntry { 187 | start: begin_phy, 188 | end, 189 | read_permission, 190 | write_permission, 191 | execute_permission, 192 | shared, 193 | name, 194 | }; 195 | result.push(entry); 196 | } 197 | } else { 198 | let entry = MapsEntry { 199 | start, 200 | end, 201 | read_permission, 202 | write_permission, 203 | execute_permission, 204 | shared, 205 | name, 206 | }; 207 | result.push(entry); 208 | } 209 | } 210 | Ok(result) 211 | } 212 | 213 | /// get the count of memory map entries. 214 | fn get_mem_map_count(&self, pid: i32) -> Result { 215 | ioctl_write_int!(get_mem_map_count, RWMEM_MAGIC, IOCTL_GET_PROCESS_MAPS_COUNT); 216 | let count = unsafe { get_mem_map_count(self.fd.as_raw_fd(), pid as u64) }?; 217 | Ok(count as usize) 218 | } 219 | 220 | /// check if the memory is physical. 221 | /// begin_addr and end_addr must be page aligned. 222 | /// return a bitvec, each bit represents a page. 223 | pub fn is_mem_phy(&self, pid: i32, begin_addr: u64, end_addr: u64) -> Result> { 224 | if begin_addr & 0xfff != 0 { 225 | return Err(errors::Error::NotAligned); 226 | } 227 | if end_addr & 0xfff != 0 { 228 | return Err(errors::Error::NotAligned); 229 | } 230 | if begin_addr >= end_addr { 231 | return Err(errors::Error::BeginLargerThanEnd(begin_addr, end_addr)); 232 | } 233 | let buf_size = max(24, ((end_addr >> 12) - (begin_addr >> 12) + 7) / 8) as usize; 234 | let mut buf = vec![0u8; buf_size]; 235 | buf[0..8].copy_from_slice(&(pid as i64).to_ne_bytes()); 236 | buf[8..16].copy_from_slice(&begin_addr.to_ne_bytes()); 237 | buf[16..24].copy_from_slice(&end_addr.to_ne_bytes()); 238 | nix::errno::Errno::result(unsafe { 239 | libc::ioctl( 240 | self.fd.as_raw_fd(), 241 | request_code_readwrite!( 242 | RWMEM_MAGIC, 243 | IOCTL_CHECK_PROCESS_ADDR_PHY, 244 | std::mem::size_of::() 245 | ), 246 | buf.as_mut_ptr(), 247 | buf_size, 248 | ) 249 | })?; 250 | let mut result = BitVec::::from_vec(buf); 251 | result.truncate(((end_addr >> 12) - (begin_addr >> 12)) as usize); 252 | Ok(result) 253 | } 254 | 255 | /// add bp 256 | pub fn add_bp( 257 | &self, 258 | pid: i32, 259 | bp_type: BreakpointType, 260 | len: u8, 261 | addr: u64, 262 | ) -> Result { 263 | let mut buf = [0u8; 16]; 264 | 265 | buf[0..4].copy_from_slice(&pid.to_ne_bytes()); 266 | buf[4] = match bp_type { 267 | BreakpointType::Read => 1, 268 | BreakpointType::Write => 2, 269 | BreakpointType::ReadWrite => 3, 270 | BreakpointType::Execute => 4, 271 | }; 272 | buf[5] = len; 273 | buf[8..16].copy_from_slice(&addr.to_ne_bytes()); 274 | let fd = nix::errno::Errno::result(unsafe { 275 | libc::ioctl( 276 | self.fd.as_raw_fd(), 277 | request_code_readwrite!(RWMEM_MAGIC, 3, std::mem::size_of::()), 278 | buf.as_ptr(), 279 | 16, 280 | ) 281 | })?; 282 | Ok(Breakpoint::from_raw_fd(fd)) 283 | } 284 | 285 | pub fn get_num_brps(&self) -> Result { 286 | ioctl_none!(get_num_brps, RWMEM_MAGIC, 4); 287 | let num = unsafe { get_num_brps(self.fd.as_raw_fd()) }?; 288 | Ok(num) 289 | } 290 | 291 | pub fn get_num_wrps(&self) -> Result { 292 | ioctl_none!(get_num_wrps, RWMEM_MAGIC, 5); 293 | let num = unsafe { get_num_wrps(self.fd.as_raw_fd()) }?; 294 | Ok(num) 295 | } 296 | } 297 | 298 | #[derive(Debug)] 299 | pub struct Breakpoint { 300 | fd: OwnedFd, 301 | } 302 | 303 | #[repr(C)] 304 | #[derive(Debug, Clone, PartialEq, Eq)] 305 | pub struct Regs { 306 | pub regs: [u64; 31], 307 | pub sp: u64, 308 | pub pc: u64, 309 | pub pstate: u64, 310 | } 311 | 312 | #[repr(C)] 313 | #[derive(Debug, Clone, PartialEq, Eq)] 314 | pub struct SimdRegs { 315 | pub regs: [u128; 32], 316 | pub fpsr: u32, 317 | pub fpcr: u32, 318 | __: [u32; 2], 319 | } 320 | 321 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 322 | pub enum BreakpointType { 323 | Read, 324 | Write, 325 | ReadWrite, 326 | Execute, 327 | } 328 | 329 | impl std::str::FromStr for BreakpointType { 330 | type Err = errors::Error; 331 | fn from_str(s: &str) -> std::result::Result { 332 | match s.to_lowercase().as_str() { 333 | "r" => Ok(Self::Read), 334 | "w" => Ok(Self::Write), 335 | "rw" => Ok(Self::ReadWrite), 336 | "x" => Ok(Self::Execute), 337 | "read" => Ok(Self::Read), 338 | "write" => Ok(Self::Write), 339 | "readwrite" => Ok(Self::ReadWrite), 340 | "read_write" => Ok(Self::ReadWrite), 341 | "execute" => Ok(Self::Execute), 342 | _ => Err(errors::Error::InvalidBreakpointType(s.to_string())), 343 | } 344 | } 345 | } 346 | 347 | pub type AllRegs = (Regs, SimdRegs); 348 | 349 | #[allow(dead_code)] 350 | impl Breakpoint { 351 | pub fn from_raw_fd(fd: RawFd) -> Self { 352 | Self { 353 | fd: unsafe { OwnedFd::from_raw_fd(fd) }, 354 | } 355 | } 356 | 357 | pub fn as_raw_fd(&self) -> RawFd { 358 | self.fd.as_raw_fd() 359 | } 360 | 361 | pub fn cont(&self) -> Result { 362 | ioctl_none!(bp_continue, RWMEM_BP_MAGIC, 0); 363 | let num = unsafe { bp_continue(self.fd.as_raw_fd()) }?; 364 | Ok(num) 365 | } 366 | 367 | pub fn set_reg(&self, reg: u8, value: u64) -> Result<()> { 368 | #[repr(C)] 369 | struct SetRegParam { 370 | reg: u64, 371 | value: u64, 372 | } 373 | ioctl_write_ptr!(bp_set_reg, RWMEM_BP_MAGIC, 1, SetRegParam); 374 | if reg >= 34 { 375 | return Err(errors::Error::InvalidRegister(reg as u64)); 376 | } 377 | let param = SetRegParam { 378 | reg: reg as u64, 379 | value, 380 | }; 381 | unsafe { bp_set_reg(self.fd.as_raw_fd(), ¶m) }?; 382 | Ok(()) 383 | } 384 | 385 | pub fn set_simd_reg(&self, reg: u8, value: u128) -> Result<()> { 386 | #[repr(C)] 387 | struct SetSimdRegParam { 388 | reg: u64, 389 | value: u128, 390 | } 391 | ioctl_write_ptr!(bp_set_simd_reg, RWMEM_BP_MAGIC, 2, SetSimdRegParam); 392 | if reg >= 34 { 393 | return Err(errors::Error::InvalidRegister(reg as u64)); 394 | } 395 | let param = SetSimdRegParam { 396 | reg: reg as u64, 397 | value, 398 | }; 399 | unsafe { bp_set_simd_reg(self.fd.as_raw_fd(), ¶m) }?; 400 | Ok(()) 401 | } 402 | 403 | pub fn get_regs(&self) -> Result { 404 | const BUF_SIZE: usize = std::mem::size_of::(); 405 | let mut buf = [0u8; BUF_SIZE]; 406 | nix::unistd::read(self.fd.as_raw_fd(), &mut buf)?; 407 | let regs = unsafe { std::mem::transmute::<[u8; BUF_SIZE], Regs>(buf) }; 408 | Ok(regs) 409 | } 410 | 411 | pub fn get_regs_with_simd(&self) -> Result<(Regs, SimdRegs)> { 412 | const BUF_SIZE: usize = std::mem::size_of::<(Regs, SimdRegs)>(); 413 | let mut buf = [0u8; BUF_SIZE]; 414 | nix::unistd::read(self.fd.as_raw_fd(), &mut buf)?; 415 | let regs = unsafe { std::mem::transmute::<[u8; BUF_SIZE], (Regs, SimdRegs)>(buf) }; 416 | Ok(regs) 417 | } 418 | 419 | #[cfg(feature = "async")] 420 | pub async fn wait(&self) -> Result<()> { 421 | let async_fd = tokio::io::unix::AsyncFd::with_interest( 422 | self.as_raw_fd(), 423 | tokio::io::Interest::READABLE, 424 | )?; 425 | async_fd.readable().await?.clear_ready(); 426 | Ok(()) 427 | } 428 | 429 | pub fn step(&self) -> Result { 430 | ioctl_none!(bp_step, RWMEM_BP_MAGIC, 3); 431 | let num = unsafe { bp_step(self.fd.as_raw_fd()) }?; 432 | Ok(num) 433 | } 434 | 435 | pub fn is_stopped(&self) -> Result { 436 | ioctl_none!(bp_is_stopped, RWMEM_BP_MAGIC, 4); 437 | let stopped = unsafe { bp_is_stopped(self.fd.as_raw_fd()) }?; 438 | Ok(stopped != 0) 439 | } 440 | } 441 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "anstream" 22 | version = "0.6.15" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" 25 | dependencies = [ 26 | "anstyle", 27 | "anstyle-parse", 28 | "anstyle-query", 29 | "anstyle-wincon", 30 | "colorchoice", 31 | "is_terminal_polyfill", 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle" 37 | version = "1.0.8" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 40 | 41 | [[package]] 42 | name = "anstyle-parse" 43 | version = "0.2.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" 46 | dependencies = [ 47 | "utf8parse", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle-query" 52 | version = "1.1.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" 55 | dependencies = [ 56 | "windows-sys", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-wincon" 61 | version = "3.0.4" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" 64 | dependencies = [ 65 | "anstyle", 66 | "windows-sys", 67 | ] 68 | 69 | [[package]] 70 | name = "anyhow" 71 | version = "1.0.86" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 74 | 75 | [[package]] 76 | name = "autocfg" 77 | version = "1.3.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 80 | 81 | [[package]] 82 | name = "backtrace" 83 | version = "0.3.73" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 86 | dependencies = [ 87 | "addr2line", 88 | "cc", 89 | "cfg-if", 90 | "libc", 91 | "miniz_oxide", 92 | "object", 93 | "rustc-demangle", 94 | ] 95 | 96 | [[package]] 97 | name = "bitflags" 98 | version = "2.6.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 101 | 102 | [[package]] 103 | name = "bitvec" 104 | version = "1.0.1" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 107 | dependencies = [ 108 | "funty", 109 | "radium", 110 | "tap", 111 | "wyz", 112 | ] 113 | 114 | [[package]] 115 | name = "byteorder" 116 | version = "1.5.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 119 | 120 | [[package]] 121 | name = "cc" 122 | version = "1.1.15" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" 125 | dependencies = [ 126 | "shlex", 127 | ] 128 | 129 | [[package]] 130 | name = "cfg-if" 131 | version = "1.0.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 134 | 135 | [[package]] 136 | name = "clap" 137 | version = "4.5.16" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" 140 | dependencies = [ 141 | "clap_builder", 142 | "clap_derive", 143 | ] 144 | 145 | [[package]] 146 | name = "clap-num" 147 | version = "1.1.1" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" 150 | dependencies = [ 151 | "num-traits", 152 | ] 153 | 154 | [[package]] 155 | name = "clap_builder" 156 | version = "4.5.15" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" 159 | dependencies = [ 160 | "anstream", 161 | "anstyle", 162 | "clap_lex", 163 | "strsim", 164 | ] 165 | 166 | [[package]] 167 | name = "clap_derive" 168 | version = "4.5.13" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" 171 | dependencies = [ 172 | "heck", 173 | "proc-macro2", 174 | "quote", 175 | "syn", 176 | ] 177 | 178 | [[package]] 179 | name = "clap_lex" 180 | version = "0.7.2" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 183 | 184 | [[package]] 185 | name = "colorchoice" 186 | version = "1.0.2" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" 189 | 190 | [[package]] 191 | name = "funty" 192 | version = "2.0.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 195 | 196 | [[package]] 197 | name = "gimli" 198 | version = "0.29.0" 199 | source = "registry+https://github.com/rust-lang/crates.io-index" 200 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 201 | 202 | [[package]] 203 | name = "heck" 204 | version = "0.5.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 207 | 208 | [[package]] 209 | name = "hermit-abi" 210 | version = "0.3.9" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 213 | 214 | [[package]] 215 | name = "hex" 216 | version = "0.4.3" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 219 | 220 | [[package]] 221 | name = "is_terminal_polyfill" 222 | version = "1.70.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 225 | 226 | [[package]] 227 | name = "libc" 228 | version = "0.2.158" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" 231 | 232 | [[package]] 233 | name = "librwmem" 234 | version = "0.1.0" 235 | dependencies = [ 236 | "bitvec", 237 | "byteorder", 238 | "libc", 239 | "nix", 240 | "thiserror", 241 | "tokio", 242 | ] 243 | 244 | [[package]] 245 | name = "memchr" 246 | version = "2.7.4" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 249 | 250 | [[package]] 251 | name = "miniz_oxide" 252 | version = "0.7.4" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 255 | dependencies = [ 256 | "adler", 257 | ] 258 | 259 | [[package]] 260 | name = "mio" 261 | version = "1.0.2" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 264 | dependencies = [ 265 | "hermit-abi", 266 | "libc", 267 | "wasi", 268 | "windows-sys", 269 | ] 270 | 271 | [[package]] 272 | name = "nix" 273 | version = "0.27.1" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" 276 | dependencies = [ 277 | "bitflags", 278 | "cfg-if", 279 | "libc", 280 | ] 281 | 282 | [[package]] 283 | name = "num-traits" 284 | version = "0.2.19" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 287 | dependencies = [ 288 | "autocfg", 289 | ] 290 | 291 | [[package]] 292 | name = "object" 293 | version = "0.36.3" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" 296 | dependencies = [ 297 | "memchr", 298 | ] 299 | 300 | [[package]] 301 | name = "pin-project-lite" 302 | version = "0.2.14" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 305 | 306 | [[package]] 307 | name = "pretty-hex" 308 | version = "0.4.1" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "bbc83ee4a840062f368f9096d80077a9841ec117e17e7f700df81958f1451254" 311 | 312 | [[package]] 313 | name = "proc-macro2" 314 | version = "1.0.86" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 317 | dependencies = [ 318 | "unicode-ident", 319 | ] 320 | 321 | [[package]] 322 | name = "quote" 323 | version = "1.0.37" 324 | source = "registry+https://github.com/rust-lang/crates.io-index" 325 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 326 | dependencies = [ 327 | "proc-macro2", 328 | ] 329 | 330 | [[package]] 331 | name = "radium" 332 | version = "0.7.0" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 335 | 336 | [[package]] 337 | name = "rustc-demangle" 338 | version = "0.1.24" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 341 | 342 | [[package]] 343 | name = "rwmemctl" 344 | version = "0.1.0" 345 | dependencies = [ 346 | "anyhow", 347 | "clap", 348 | "clap-num", 349 | "hex", 350 | "librwmem", 351 | "pretty-hex", 352 | "shellish_parse", 353 | "tokio", 354 | ] 355 | 356 | [[package]] 357 | name = "shellish_parse" 358 | version = "2.2.0" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "4c29b912ad681a28566f37b936bba1f3580a93b9391c4a0b12cb1c6b4ed79973" 361 | 362 | [[package]] 363 | name = "shlex" 364 | version = "1.3.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 367 | 368 | [[package]] 369 | name = "socket2" 370 | version = "0.5.7" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 373 | dependencies = [ 374 | "libc", 375 | "windows-sys", 376 | ] 377 | 378 | [[package]] 379 | name = "strsim" 380 | version = "0.11.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 383 | 384 | [[package]] 385 | name = "syn" 386 | version = "2.0.76" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" 389 | dependencies = [ 390 | "proc-macro2", 391 | "quote", 392 | "unicode-ident", 393 | ] 394 | 395 | [[package]] 396 | name = "tap" 397 | version = "1.0.1" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 400 | 401 | [[package]] 402 | name = "thiserror" 403 | version = "1.0.63" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 406 | dependencies = [ 407 | "thiserror-impl", 408 | ] 409 | 410 | [[package]] 411 | name = "thiserror-impl" 412 | version = "1.0.63" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 415 | dependencies = [ 416 | "proc-macro2", 417 | "quote", 418 | "syn", 419 | ] 420 | 421 | [[package]] 422 | name = "tokio" 423 | version = "1.39.3" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" 426 | dependencies = [ 427 | "backtrace", 428 | "libc", 429 | "mio", 430 | "pin-project-lite", 431 | "socket2", 432 | "tokio-macros", 433 | "windows-sys", 434 | ] 435 | 436 | [[package]] 437 | name = "tokio-macros" 438 | version = "2.4.0" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 441 | dependencies = [ 442 | "proc-macro2", 443 | "quote", 444 | "syn", 445 | ] 446 | 447 | [[package]] 448 | name = "unicode-ident" 449 | version = "1.0.12" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 452 | 453 | [[package]] 454 | name = "utf8parse" 455 | version = "0.2.2" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 458 | 459 | [[package]] 460 | name = "wasi" 461 | version = "0.11.0+wasi-snapshot-preview1" 462 | source = "registry+https://github.com/rust-lang/crates.io-index" 463 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 464 | 465 | [[package]] 466 | name = "windows-sys" 467 | version = "0.52.0" 468 | source = "registry+https://github.com/rust-lang/crates.io-index" 469 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 470 | dependencies = [ 471 | "windows-targets", 472 | ] 473 | 474 | [[package]] 475 | name = "windows-targets" 476 | version = "0.52.6" 477 | source = "registry+https://github.com/rust-lang/crates.io-index" 478 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 479 | dependencies = [ 480 | "windows_aarch64_gnullvm", 481 | "windows_aarch64_msvc", 482 | "windows_i686_gnu", 483 | "windows_i686_gnullvm", 484 | "windows_i686_msvc", 485 | "windows_x86_64_gnu", 486 | "windows_x86_64_gnullvm", 487 | "windows_x86_64_msvc", 488 | ] 489 | 490 | [[package]] 491 | name = "windows_aarch64_gnullvm" 492 | version = "0.52.6" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 495 | 496 | [[package]] 497 | name = "windows_aarch64_msvc" 498 | version = "0.52.6" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 501 | 502 | [[package]] 503 | name = "windows_i686_gnu" 504 | version = "0.52.6" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 507 | 508 | [[package]] 509 | name = "windows_i686_gnullvm" 510 | version = "0.52.6" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 513 | 514 | [[package]] 515 | name = "windows_i686_msvc" 516 | version = "0.52.6" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 519 | 520 | [[package]] 521 | name = "windows_x86_64_gnu" 522 | version = "0.52.6" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 525 | 526 | [[package]] 527 | name = "windows_x86_64_gnullvm" 528 | version = "0.52.6" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 531 | 532 | [[package]] 533 | name = "windows_x86_64_msvc" 534 | version = "0.52.6" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 537 | 538 | [[package]] 539 | name = "wyz" 540 | version = "0.5.1" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 543 | dependencies = [ 544 | "tap", 545 | ] 546 | -------------------------------------------------------------------------------- /CEServer/MemoryReaderWriter37.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MEMORY_READER_WRITER_H_ 2 | #define MEMORY_READER_WRITER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "IMemReaderWriterProxy.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | // 默认驱动文件名 23 | #define RWPROCMEM_FILE_NODE "/dev/rwMem" 24 | 25 | // 安静输出模式 26 | #define QUIET_PRINTF 27 | 28 | #ifdef QUIET_PRINTF 29 | #undef TRACE 30 | #define TRACE(fmt, ...) 31 | #else 32 | #define TRACE(fmt, ...) printf(fmt, ##__VA_ARGS__) 33 | #endif 34 | 35 | #define MAJOR_NUM 100 36 | #define IOCTL_GET_PROCESS_MAPS_COUNT _IOWR(MAJOR_NUM, 0, char *) // 获取进程的内存块地址数量 37 | #define IOCTL_GET_PROCESS_MAPS_LIST _IOWR(MAJOR_NUM, 1, char *) // 获取进程的内存块地址列表 38 | #define IOCTL_CHECK_PROCESS_ADDR_PHY _IOWR(MAJOR_NUM, 2, char *) // 检查进程内存是否有物理内存位置 39 | 40 | class CMemoryReaderWriter { 41 | public: 42 | CMemoryReaderWriter() {} 43 | ~CMemoryReaderWriter() { DisconnectDriver(); } 44 | 45 | // 连接驱动(驱动节点文件路径名,是否使用躲避SELinux的通信方式,错误代码,机器码ID),返回值:驱动连接句柄,>=0代表成功 46 | BOOL ConnectDriver(const char *lpszDriverFileNodePath, BOOL bUseBypassSELinuxMode, int &err) { 47 | if (m_nDriverLink >= 0) { 48 | return TRUE; 49 | } 50 | m_nDriverLink = _rwProcMemDriver_Connect(lpszDriverFileNodePath); 51 | if (m_nDriverLink < 0) { 52 | err = m_nDriverLink; 53 | return FALSE; 54 | } 55 | _rwProcMemDriver_UseBypassSELinuxMode(bUseBypassSELinuxMode); 56 | err = 0; 57 | return TRUE; 58 | } 59 | 60 | // 断开驱动,返回值:TRUE成功,FALSE失败 61 | BOOL DisconnectDriver() { 62 | if (m_nDriverLink >= 0) { 63 | _rwProcMemDriver_Disconnect(m_nDriverLink); 64 | m_nDriverLink = -1; 65 | return TRUE; 66 | } else { 67 | return FALSE; 68 | } 69 | } 70 | 71 | // 驱动是否连接正常,返回值:TRUE已连接,FALSE未连接 72 | BOOL IsDriverConnected() { return m_nDriverLink >= 0; } 73 | 74 | // 驱动_打开进程(进程PID),返回值:进程句柄,0为失败 75 | uint64_t OpenProcess(uint64_t pid) { return pid; } 76 | 77 | // 驱动_读取进程内存(进程句柄,进程内存地址,读取结果缓冲区,读取结果缓冲区大小,实际读取字节数,是否暴力读取),返回值:TRUE成功,FALSE失败 78 | BOOL ReadProcessMemory(uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesRead = NULL, BOOL bIsForceRead = FALSE) { 79 | return _rwProcMemDriver_ReadProcessMemory(m_nDriverLink, hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, bIsForceRead); 80 | } 81 | 82 | // 驱动_读取进程内存_单线程极速版(进程句柄,进程内存地址,读取结果缓冲区,读取结果缓冲区大小,实际读取字节数,是否暴力读取),返回值:TRUE成功,FALSE失败 83 | BOOL ReadProcessMemory_Fast(uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesRead = NULL, BOOL bIsForceRead = FALSE) { 84 | return _rwProcMemDriver_ReadProcessMemory_Fast(m_nDriverLink, hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, bIsForceRead); 85 | } 86 | 87 | // 驱动_写入进程内存(进程句柄,进程内存地址,写入数据缓冲区,写入数据缓冲区大小,实际写入字节数,是否暴力写入),返回值:TRUE成功,FALSE失败 88 | BOOL WriteProcessMemory(uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesWritten = NULL, BOOL bIsForceWrite = FALSE) { 89 | return _rwProcMemDriver_WriteProcessMemory(m_nDriverLink, hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten, bIsForceWrite); 90 | } 91 | 92 | // 驱动_写入进程内存_单线程极速版(进程句柄,进程内存地址,写入数据缓冲区,写入数据缓冲区大小,实际写入字节数,是否暴力写入),返回值:TRUE成功,FALSE失败 93 | BOOL WriteProcessMemory_Fast(uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesWritten = NULL, BOOL bIsForceWrite = FALSE) { 94 | return _rwProcMemDriver_WriteProcessMemory_Fast(m_nDriverLink, hProcess, lpBaseAddress, lpBuffer, nSize, lpNumberOfBytesWritten, bIsForceWrite); 95 | } 96 | 97 | // 驱动_关闭进程(进程句柄),返回值:TRUE成功,FALSE失败 98 | BOOL CloseHandle(uint64_t hProcess) { return TRUE; } 99 | 100 | // 驱动_获取进程内存块列表(进程句柄,是否仅显示物理内存,输出缓冲区,输出是否完整),返回值:TRUE成功,FALSE失败 101 | // (参数showPhy说明: FALSE为显示全部内存,TRUE为只显示在物理内存中的内存,注意:如果进程内存不存在于物理内存中,驱动将无法读取该内存位置的值) 102 | // (参数bOutListCompleted说明: 若输出FALSE,则代表输出缓冲区里的进程内存块列表不完整,若输出TRUE,则代表输出缓冲区里的进程内存块列表完整可靠) 103 | BOOL VirtualQueryExFull(uint64_t hProcess, BOOL showPhy, std::vector &vOutput, BOOL &bOutListCompleted) { 104 | return _rwProcMemDriver_VirtualQueryExFull(m_nDriverLink, hProcess, showPhy, vOutput, &bOutListCompleted); 105 | } 106 | 107 | // 获取驱动连接FD,返回值:驱动连接的FD 108 | int GetLinkFD() { return m_nDriverLink; } 109 | 110 | // 设置驱动连接FD 111 | void SetLinkFD(int fd) { m_nDriverLink = fd; } 112 | 113 | // 设置是否使用躲避SELinux的通信方式 114 | void SeUseBypassSELinuxMode(BOOL bUseBypassSELinuxMode) { _rwProcMemDriver_UseBypassSELinuxMode(bUseBypassSELinuxMode); } 115 | 116 | private: 117 | int _rwProcMemDriver_MyIoctl(int fd, unsigned int cmd, unsigned long buf, unsigned long bufSize) { 118 | if (m_bUseBypassSELinuxMode == TRUE) { 119 | // 驱动通信方式:lseek,躲开系统SELinux拦截 120 | char *lseekBuf = (char *)malloc(sizeof(cmd) + bufSize); 121 | *(unsigned long *)lseekBuf = cmd; 122 | memcpy((void *)((size_t)lseekBuf + (size_t)sizeof(cmd)), (void *)buf, bufSize); 123 | uint64_t ret = lseek64(fd, (off64_t)lseekBuf, SEEK_CUR); 124 | memcpy((void *)buf, (void *)((size_t)lseekBuf + (size_t)sizeof(cmd)), bufSize); 125 | free(lseekBuf); 126 | return ret; 127 | } else { 128 | // 驱动通信方式:ioctl 129 | return ioctl(fd, cmd, buf); 130 | } 131 | } 132 | 133 | int _rwProcMemDriver_Connect(const char *lpszDriverFileNodePath) { 134 | int nDriverLink = open(lpszDriverFileNodePath, O_RDWR); 135 | if (nDriverLink < 0) { 136 | int last_err = errno; 137 | if (last_err == EACCES) { 138 | chmod(lpszDriverFileNodePath, 666); 139 | nDriverLink = open(lpszDriverFileNodePath, O_RDWR); 140 | last_err = errno; 141 | chmod(lpszDriverFileNodePath, 0600); 142 | } 143 | if (nDriverLink < 0) { 144 | TRACE("open error():%s\n", strerror(last_err)); 145 | return -last_err; 146 | } 147 | } 148 | return nDriverLink; 149 | } 150 | 151 | BOOL _rwProcMemDriver_Disconnect(int nDriverLink) { 152 | if (nDriverLink < 0) { 153 | return FALSE; 154 | } 155 | close(nDriverLink); 156 | return TRUE; 157 | } 158 | 159 | void _rwProcMemDriver_UseBypassSELinuxMode(BOOL bUseBypassSELinuxMode) { m_bUseBypassSELinuxMode = bUseBypassSELinuxMode; } 160 | BOOL _rwProcMemDriver_ReadProcessMemory(int nDriverLink, uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesRead, 161 | BOOL bIsForceRead) { 162 | 163 | if (lpBaseAddress <= 0) { 164 | return FALSE; 165 | } 166 | if (nDriverLink < 0) { 167 | return FALSE; 168 | } 169 | if (!hProcess) { 170 | return FALSE; 171 | } 172 | if (nSize <= 0) { 173 | return FALSE; 174 | } 175 | if (nSize < 17) { 176 | char *buf = (char *)calloc(1, 17); 177 | *(uint64_t *)&buf[0] = hProcess; 178 | *(uint64_t *)&buf[8] = lpBaseAddress; 179 | buf[16] = bIsForceRead == TRUE ? '\x01' : '\x00'; 180 | ssize_t realRead = read(nDriverLink, buf, nSize); 181 | if (realRead <= 0) { 182 | TRACE("read(): %s\n", strerror(errno)); 183 | free(buf); 184 | return FALSE; 185 | } 186 | if (realRead > 0) { 187 | memcpy(lpBuffer, buf, realRead); 188 | } 189 | 190 | if (lpNumberOfBytesRead) { 191 | *lpNumberOfBytesRead = realRead; 192 | } 193 | free(buf); 194 | } else { 195 | char *buf = (char *)lpBuffer; 196 | *(uint64_t *)&buf[0] = hProcess; 197 | *(uint64_t *)&buf[8] = lpBaseAddress; 198 | buf[16] = bIsForceRead == TRUE ? '\x01' : '\x00'; 199 | ssize_t realRead = read(nDriverLink, buf, nSize); 200 | if (realRead <= 0) { 201 | TRACE("read(): %s\n", strerror(errno)); 202 | return FALSE; 203 | } 204 | 205 | if (lpNumberOfBytesRead) { 206 | *lpNumberOfBytesRead = realRead; 207 | } 208 | } 209 | return TRUE; 210 | } 211 | 212 | BOOL _rwProcMemDriver_ReadProcessMemory_Fast(int nDriverLink, uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesRead, 213 | BOOL bIsForceRead) { 214 | 215 | if (lpBaseAddress <= 0) { 216 | return FALSE; 217 | } 218 | if (nDriverLink < 0) { 219 | return FALSE; 220 | } 221 | if (!hProcess) { 222 | return FALSE; 223 | } 224 | if (nSize <= 0) { 225 | return FALSE; 226 | } 227 | int bufSize = nSize < 17 ? 17 : nSize; 228 | 229 | // 上一次读内存申请的缓冲区,下一次继续用,可以提速 230 | static char *lastMallocReadMemBuf = NULL; 231 | static size_t lastMallocReadMemSize = 0; 232 | 233 | if (lastMallocReadMemSize < bufSize) { 234 | if (lastMallocReadMemBuf) { 235 | free(lastMallocReadMemBuf); 236 | } 237 | lastMallocReadMemBuf = (char *)malloc(bufSize); 238 | lastMallocReadMemSize = bufSize; 239 | } 240 | memset(lastMallocReadMemBuf, 0, bufSize); 241 | *(uint64_t *)&lastMallocReadMemBuf[0] = hProcess; 242 | *(uint64_t *)&lastMallocReadMemBuf[8] = lpBaseAddress; 243 | lastMallocReadMemBuf[16] = bIsForceRead == TRUE ? '\x01' : '\x00'; 244 | 245 | ssize_t realRead = read(nDriverLink, lastMallocReadMemBuf, nSize); 246 | 247 | if (realRead <= 0) { 248 | TRACE("read(): %s\n", strerror(errno)); 249 | return FALSE; 250 | } 251 | if (realRead > 0) { 252 | memcpy(lpBuffer, lastMallocReadMemBuf, realRead); 253 | } 254 | 255 | if (lpNumberOfBytesRead) { 256 | *lpNumberOfBytesRead = realRead; 257 | } 258 | return TRUE; 259 | } 260 | 261 | BOOL _rwProcMemDriver_WriteProcessMemory(int nDriverLink, uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesWritten, 262 | BOOL bIsForceWrite) { 263 | if (lpBaseAddress <= 0) { 264 | return FALSE; 265 | } 266 | if (nDriverLink < 0) { 267 | return FALSE; 268 | } 269 | if (!hProcess) { 270 | return FALSE; 271 | } 272 | if (nSize <= 0) { 273 | return FALSE; 274 | } 275 | int bufSize = nSize + 17; 276 | 277 | char *buf = (char *)malloc(bufSize); 278 | memset(buf, 0, bufSize); 279 | *(uint64_t *)&buf[0] = hProcess; 280 | *(uint64_t *)&buf[8] = lpBaseAddress; 281 | buf[16] = bIsForceWrite == TRUE ? '\x01' : '\x00'; 282 | memcpy((void *)((size_t)buf + (size_t)17), lpBuffer, nSize); 283 | 284 | ssize_t realWrite = write(nDriverLink, buf, nSize); 285 | if (realWrite <= 0) { 286 | TRACE("write(): %s\n", strerror(errno)); 287 | free(buf); 288 | return FALSE; 289 | } 290 | 291 | if (lpNumberOfBytesWritten) { 292 | *lpNumberOfBytesWritten = realWrite; 293 | } 294 | free(buf); 295 | return TRUE; 296 | } 297 | BOOL _rwProcMemDriver_WriteProcessMemory_Fast(int nDriverLink, uint64_t hProcess, uint64_t lpBaseAddress, void *lpBuffer, size_t nSize, size_t *lpNumberOfBytesWritten, 298 | BOOL bIsForceWrite) { 299 | if (lpBaseAddress <= 0) { 300 | return FALSE; 301 | } 302 | if (nDriverLink < 0) { 303 | return FALSE; 304 | } 305 | if (!hProcess) { 306 | return FALSE; 307 | } 308 | if (nSize <= 0) { 309 | return FALSE; 310 | } 311 | int bufSize = nSize + 17; 312 | 313 | // 上一次读内存申请的缓冲区,下一次继续用,可以提速 314 | static char *lastMallocWriteMemBuf = NULL; 315 | static size_t lastMallocWriteMemSize = 0; 316 | 317 | if (lastMallocWriteMemSize < bufSize) { 318 | if (lastMallocWriteMemBuf) { 319 | free(lastMallocWriteMemBuf); 320 | } 321 | lastMallocWriteMemBuf = (char *)malloc(bufSize); 322 | lastMallocWriteMemSize = bufSize; 323 | } 324 | *(uint64_t *)&lastMallocWriteMemBuf[0] = hProcess; 325 | *(uint64_t *)&lastMallocWriteMemBuf[8] = lpBaseAddress; 326 | lastMallocWriteMemBuf[16] = bIsForceWrite == TRUE ? '\x01' : '\x00'; 327 | memcpy((void *)((size_t)lastMallocWriteMemBuf + (size_t)17), lpBuffer, nSize); 328 | 329 | ssize_t realWrite = write(nDriverLink, lastMallocWriteMemBuf, nSize); 330 | if (realWrite <= 0) { 331 | TRACE("write(): %s\n", strerror(errno)); 332 | return FALSE; 333 | } 334 | 335 | if (lpNumberOfBytesWritten) { 336 | *lpNumberOfBytesWritten = realWrite; 337 | } 338 | return TRUE; 339 | } 340 | 341 | BOOL _rwProcMemDriver_VirtualQueryExFull(int nDriverLink, uint64_t hProcess, BOOL showPhy, std::vector &vOutput, BOOL *bOutListCompleted) { 342 | if (nDriverLink < 0) { 343 | return FALSE; 344 | } 345 | if (!hProcess) { 346 | return FALSE; 347 | } 348 | int count = _rwProcMemDriver_MyIoctl(nDriverLink, IOCTL_GET_PROCESS_MAPS_COUNT, (unsigned long)hProcess, sizeof(hProcess)); 349 | TRACE("VirtualQueryExFull count %d\n", count); 350 | if (count <= 0) { 351 | TRACE("VirtualQueryExFull ioctl():%s\n", strerror(errno)); 352 | return FALSE; 353 | } 354 | 355 | uint64_t big_buf_len = 8 + (8 + 8 + 4 + 512) * (count + 50); 356 | char *big_buf = (char *)calloc(1, big_buf_len); 357 | *(uint64_t *)&big_buf[0] = hProcess; 358 | 359 | uint64_t name_len = 512; 360 | *(uint64_t *)&big_buf[8] = name_len; 361 | *(uint64_t *)&big_buf[16] = big_buf_len; 362 | 363 | int unfinish = _rwProcMemDriver_MyIoctl(nDriverLink, IOCTL_GET_PROCESS_MAPS_LIST, (unsigned long)big_buf, big_buf_len); 364 | TRACE("VirtualQueryExFull unfinish %d\n", unfinish); 365 | if (unfinish < 0) { 366 | TRACE("VirtualQueryExFull ioctl():%s\n", strerror(errno)); 367 | free(big_buf); 368 | return FALSE; 369 | } 370 | size_t copy_pos = (size_t)big_buf; 371 | uint64_t res = *(uint64_t *)big_buf; 372 | *bOutListCompleted = unfinish; 373 | copy_pos += 8; 374 | for (; res > 0; res--) { 375 | uint64_t vma_start = 0; 376 | uint64_t vma_end = 0; 377 | char vma_flags[4] = {0}; 378 | char name[512] = {0}; 379 | 380 | vma_start = *(uint64_t *)copy_pos; 381 | copy_pos += 8; 382 | vma_end = *(uint64_t *)copy_pos; 383 | copy_pos += 8; 384 | memcpy(&vma_flags, (void *)copy_pos, 4); 385 | copy_pos += 4; 386 | memcpy(&name, (void *)copy_pos, 512); 387 | name[sizeof(name) - 1] = '\0'; 388 | copy_pos += 512; 389 | 390 | DRIVER_REGION_INFO rInfo = {0}; 391 | rInfo.baseaddress = vma_start; 392 | rInfo.size = vma_end - vma_start; 393 | if (vma_flags[2] == '\x01') { 394 | // executable 395 | if (vma_flags[1] == '\x01') { 396 | rInfo.protection = PAGE_EXECUTE_READWRITE; 397 | } else { 398 | rInfo.protection = PAGE_EXECUTE_READ; 399 | } 400 | } else { 401 | // not executable 402 | if (vma_flags[1] == '\x01') { 403 | rInfo.protection = PAGE_READWRITE; 404 | } else if (vma_flags[0] == '\x01') { 405 | rInfo.protection = PAGE_READONLY; 406 | } else { 407 | rInfo.protection = PAGE_NOACCESS; 408 | } 409 | } 410 | if (vma_flags[3] == '\x01') { 411 | rInfo.type = MEM_MAPPED; 412 | } else { 413 | rInfo.type = MEM_PRIVATE; 414 | } 415 | memcpy(&rInfo.name, &name, 512); 416 | rInfo.name[sizeof(rInfo.name) - 1] = '\0'; 417 | if (showPhy) { 418 | // 只显示在物理内存中的内存 419 | DRIVER_REGION_INFO rPhyInfo = {0}; 420 | 421 | uint64_t addr; 422 | int isPhyRegion = 0; 423 | char *isphy = _rwProcMemDriver_CheckMemAddrIsValid(nDriverLink, hProcess, vma_start, vma_end); 424 | if(!isphy) { 425 | continue; 426 | } 427 | int i; 428 | for (addr = vma_start, i = 0; addr < vma_end; addr += getpagesize(), i++) { 429 | if (isphy[i / 8] & ((char)1 << (i % 8))) { 430 | if (isPhyRegion == 0) { 431 | isPhyRegion = 1; 432 | rPhyInfo.baseaddress = addr; 433 | rPhyInfo.protection = rInfo.protection; 434 | rPhyInfo.type = rInfo.type; 435 | strcpy(rPhyInfo.name, rInfo.name); 436 | } 437 | 438 | } else { 439 | if (isPhyRegion == 1) { 440 | isPhyRegion = 0; 441 | rPhyInfo.size = addr - rPhyInfo.baseaddress; 442 | vOutput.push_back(rPhyInfo); 443 | } 444 | } 445 | } 446 | 447 | if (isPhyRegion == 1) { 448 | // all vma region inside phy memory 449 | rPhyInfo.size = vma_end - rPhyInfo.baseaddress; 450 | vOutput.push_back(rPhyInfo); 451 | } 452 | delete[] isphy; 453 | 454 | } else { 455 | // 显示全部内存 456 | vOutput.push_back(rInfo); 457 | } 458 | } 459 | free(big_buf); 460 | 461 | return !unfinish; 462 | } 463 | 464 | char *_rwProcMemDriver_CheckMemAddrIsValid(int nDriverLink, uint64_t hProcess, uint64_t BeginAddress, uint64_t EndAddress) { 465 | if (nDriverLink < 0) { 466 | return FALSE; 467 | } 468 | if (!hProcess) { 469 | return FALSE; 470 | } 471 | size_t bufSize = std::max(24, ((EndAddress/getpagesize()) - (BeginAddress/getpagesize()) + 7) / 8); 472 | char *ptr_buf = new char[bufSize]; 473 | *(uint64_t *)&ptr_buf[0] = hProcess; 474 | *(uint64_t *)&ptr_buf[8] = BeginAddress; 475 | *(uint64_t *)&ptr_buf[16] = EndAddress; 476 | int r = _rwProcMemDriver_MyIoctl(nDriverLink, IOCTL_CHECK_PROCESS_ADDR_PHY, (unsigned long)ptr_buf, bufSize); 477 | if (r > 0) { 478 | return ptr_buf; 479 | } 480 | return nullptr; 481 | } 482 | 483 | private: 484 | int m_nDriverLink = -1; 485 | BOOL m_bUseBypassSELinuxMode = FALSE; // 记录是否有SELinux拦截 486 | }; 487 | 488 | #endif /* MEMORY_READER_WRITER_H_ */ 489 | -------------------------------------------------------------------------------- /librwmem/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "anstream" 22 | version = "0.6.15" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" 25 | dependencies = [ 26 | "anstyle", 27 | "anstyle-parse", 28 | "anstyle-query", 29 | "anstyle-wincon", 30 | "colorchoice", 31 | "is_terminal_polyfill", 32 | "utf8parse", 33 | ] 34 | 35 | [[package]] 36 | name = "anstyle" 37 | version = "1.0.8" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" 40 | 41 | [[package]] 42 | name = "anstyle-parse" 43 | version = "0.2.5" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" 46 | dependencies = [ 47 | "utf8parse", 48 | ] 49 | 50 | [[package]] 51 | name = "anstyle-query" 52 | version = "1.1.1" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" 55 | dependencies = [ 56 | "windows-sys", 57 | ] 58 | 59 | [[package]] 60 | name = "anstyle-wincon" 61 | version = "3.0.4" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" 64 | dependencies = [ 65 | "anstyle", 66 | "windows-sys", 67 | ] 68 | 69 | [[package]] 70 | name = "anyhow" 71 | version = "1.0.86" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" 74 | 75 | [[package]] 76 | name = "autocfg" 77 | version = "1.3.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 80 | 81 | [[package]] 82 | name = "backtrace" 83 | version = "0.3.73" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 86 | dependencies = [ 87 | "addr2line", 88 | "cc", 89 | "cfg-if", 90 | "libc", 91 | "miniz_oxide", 92 | "object", 93 | "rustc-demangle", 94 | ] 95 | 96 | [[package]] 97 | name = "bitflags" 98 | version = "2.6.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 101 | 102 | [[package]] 103 | name = "bitvec" 104 | version = "1.0.1" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 107 | dependencies = [ 108 | "funty", 109 | "radium", 110 | "tap", 111 | "wyz", 112 | ] 113 | 114 | [[package]] 115 | name = "byteorder" 116 | version = "1.5.0" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 119 | 120 | [[package]] 121 | name = "cc" 122 | version = "1.1.14" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" 125 | dependencies = [ 126 | "shlex", 127 | ] 128 | 129 | [[package]] 130 | name = "cfg-if" 131 | version = "1.0.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 134 | 135 | [[package]] 136 | name = "cfg_aliases" 137 | version = "0.1.1" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" 140 | 141 | [[package]] 142 | name = "clap" 143 | version = "4.5.16" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" 146 | dependencies = [ 147 | "clap_builder", 148 | "clap_derive", 149 | ] 150 | 151 | [[package]] 152 | name = "clap-num" 153 | version = "1.1.1" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "0e063d263364859dc54fb064cedb7c122740cd4733644b14b176c097f51e8ab7" 156 | dependencies = [ 157 | "num-traits", 158 | ] 159 | 160 | [[package]] 161 | name = "clap_builder" 162 | version = "4.5.15" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" 165 | dependencies = [ 166 | "anstream", 167 | "anstyle", 168 | "clap_lex", 169 | "strsim", 170 | ] 171 | 172 | [[package]] 173 | name = "clap_derive" 174 | version = "4.5.13" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" 177 | dependencies = [ 178 | "heck", 179 | "proc-macro2", 180 | "quote", 181 | "syn", 182 | ] 183 | 184 | [[package]] 185 | name = "clap_lex" 186 | version = "0.7.2" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" 189 | 190 | [[package]] 191 | name = "clipboard-win" 192 | version = "5.4.0" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" 195 | dependencies = [ 196 | "error-code", 197 | ] 198 | 199 | [[package]] 200 | name = "colorchoice" 201 | version = "1.0.2" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" 204 | 205 | [[package]] 206 | name = "endian-type" 207 | version = "0.1.2" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" 210 | 211 | [[package]] 212 | name = "errno" 213 | version = "0.3.9" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 216 | dependencies = [ 217 | "libc", 218 | "windows-sys", 219 | ] 220 | 221 | [[package]] 222 | name = "error-code" 223 | version = "3.2.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" 226 | 227 | [[package]] 228 | name = "fd-lock" 229 | version = "4.0.2" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" 232 | dependencies = [ 233 | "cfg-if", 234 | "rustix", 235 | "windows-sys", 236 | ] 237 | 238 | [[package]] 239 | name = "funty" 240 | version = "2.0.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 243 | 244 | [[package]] 245 | name = "gimli" 246 | version = "0.29.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 249 | 250 | [[package]] 251 | name = "heck" 252 | version = "0.5.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 255 | 256 | [[package]] 257 | name = "hermit-abi" 258 | version = "0.3.9" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 261 | 262 | [[package]] 263 | name = "hex" 264 | version = "0.4.3" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 267 | 268 | [[package]] 269 | name = "home" 270 | version = "0.5.9" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" 273 | dependencies = [ 274 | "windows-sys", 275 | ] 276 | 277 | [[package]] 278 | name = "is_terminal_polyfill" 279 | version = "1.70.1" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 282 | 283 | [[package]] 284 | name = "libc" 285 | version = "0.2.158" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" 288 | 289 | [[package]] 290 | name = "librwmem" 291 | version = "0.1.0" 292 | dependencies = [ 293 | "anyhow", 294 | "bitvec", 295 | "byteorder", 296 | "clap", 297 | "clap-num", 298 | "hex", 299 | "libc", 300 | "nix 0.27.1", 301 | "pretty-hex", 302 | "rustyline", 303 | "shellish_parse", 304 | "thiserror", 305 | "tokio", 306 | ] 307 | 308 | [[package]] 309 | name = "linux-raw-sys" 310 | version = "0.4.14" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 313 | 314 | [[package]] 315 | name = "log" 316 | version = "0.4.22" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 319 | 320 | [[package]] 321 | name = "memchr" 322 | version = "2.7.4" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 325 | 326 | [[package]] 327 | name = "miniz_oxide" 328 | version = "0.7.4" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 331 | dependencies = [ 332 | "adler", 333 | ] 334 | 335 | [[package]] 336 | name = "mio" 337 | version = "1.0.2" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 340 | dependencies = [ 341 | "hermit-abi", 342 | "libc", 343 | "wasi", 344 | "windows-sys", 345 | ] 346 | 347 | [[package]] 348 | name = "nibble_vec" 349 | version = "0.1.0" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" 352 | dependencies = [ 353 | "smallvec", 354 | ] 355 | 356 | [[package]] 357 | name = "nix" 358 | version = "0.27.1" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" 361 | dependencies = [ 362 | "bitflags", 363 | "cfg-if", 364 | "libc", 365 | ] 366 | 367 | [[package]] 368 | name = "nix" 369 | version = "0.28.0" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" 372 | dependencies = [ 373 | "bitflags", 374 | "cfg-if", 375 | "cfg_aliases", 376 | "libc", 377 | ] 378 | 379 | [[package]] 380 | name = "num-traits" 381 | version = "0.2.19" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 384 | dependencies = [ 385 | "autocfg", 386 | ] 387 | 388 | [[package]] 389 | name = "object" 390 | version = "0.36.3" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" 393 | dependencies = [ 394 | "memchr", 395 | ] 396 | 397 | [[package]] 398 | name = "pin-project-lite" 399 | version = "0.2.14" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 402 | 403 | [[package]] 404 | name = "pretty-hex" 405 | version = "0.4.1" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "bbc83ee4a840062f368f9096d80077a9841ec117e17e7f700df81958f1451254" 408 | 409 | [[package]] 410 | name = "proc-macro2" 411 | version = "1.0.86" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 414 | dependencies = [ 415 | "unicode-ident", 416 | ] 417 | 418 | [[package]] 419 | name = "quote" 420 | version = "1.0.37" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 423 | dependencies = [ 424 | "proc-macro2", 425 | ] 426 | 427 | [[package]] 428 | name = "radium" 429 | version = "0.7.0" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 432 | 433 | [[package]] 434 | name = "radix_trie" 435 | version = "0.2.1" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" 438 | dependencies = [ 439 | "endian-type", 440 | "nibble_vec", 441 | ] 442 | 443 | [[package]] 444 | name = "rustc-demangle" 445 | version = "0.1.24" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 448 | 449 | [[package]] 450 | name = "rustix" 451 | version = "0.38.34" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 454 | dependencies = [ 455 | "bitflags", 456 | "errno", 457 | "libc", 458 | "linux-raw-sys", 459 | "windows-sys", 460 | ] 461 | 462 | [[package]] 463 | name = "rustyline" 464 | version = "14.0.0" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" 467 | dependencies = [ 468 | "bitflags", 469 | "cfg-if", 470 | "clipboard-win", 471 | "fd-lock", 472 | "home", 473 | "libc", 474 | "log", 475 | "memchr", 476 | "nix 0.28.0", 477 | "radix_trie", 478 | "termios", 479 | "unicode-segmentation", 480 | "unicode-width", 481 | "utf8parse", 482 | "windows-sys", 483 | ] 484 | 485 | [[package]] 486 | name = "shellish_parse" 487 | version = "2.2.0" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "4c29b912ad681a28566f37b936bba1f3580a93b9391c4a0b12cb1c6b4ed79973" 490 | 491 | [[package]] 492 | name = "shlex" 493 | version = "1.3.0" 494 | source = "registry+https://github.com/rust-lang/crates.io-index" 495 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 496 | 497 | [[package]] 498 | name = "smallvec" 499 | version = "1.13.2" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 502 | 503 | [[package]] 504 | name = "socket2" 505 | version = "0.5.7" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 508 | dependencies = [ 509 | "libc", 510 | "windows-sys", 511 | ] 512 | 513 | [[package]] 514 | name = "strsim" 515 | version = "0.11.1" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 518 | 519 | [[package]] 520 | name = "syn" 521 | version = "2.0.76" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" 524 | dependencies = [ 525 | "proc-macro2", 526 | "quote", 527 | "unicode-ident", 528 | ] 529 | 530 | [[package]] 531 | name = "tap" 532 | version = "1.0.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 535 | 536 | [[package]] 537 | name = "termios" 538 | version = "0.3.3" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" 541 | dependencies = [ 542 | "libc", 543 | ] 544 | 545 | [[package]] 546 | name = "thiserror" 547 | version = "1.0.63" 548 | source = "registry+https://github.com/rust-lang/crates.io-index" 549 | checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" 550 | dependencies = [ 551 | "thiserror-impl", 552 | ] 553 | 554 | [[package]] 555 | name = "thiserror-impl" 556 | version = "1.0.63" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" 559 | dependencies = [ 560 | "proc-macro2", 561 | "quote", 562 | "syn", 563 | ] 564 | 565 | [[package]] 566 | name = "tokio" 567 | version = "1.39.3" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" 570 | dependencies = [ 571 | "backtrace", 572 | "libc", 573 | "mio", 574 | "pin-project-lite", 575 | "socket2", 576 | "windows-sys", 577 | ] 578 | 579 | [[package]] 580 | name = "unicode-ident" 581 | version = "1.0.12" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 584 | 585 | [[package]] 586 | name = "unicode-segmentation" 587 | version = "1.11.0" 588 | source = "registry+https://github.com/rust-lang/crates.io-index" 589 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 590 | 591 | [[package]] 592 | name = "unicode-width" 593 | version = "0.1.13" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 596 | 597 | [[package]] 598 | name = "utf8parse" 599 | version = "0.2.2" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 602 | 603 | [[package]] 604 | name = "wasi" 605 | version = "0.11.0+wasi-snapshot-preview1" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 608 | 609 | [[package]] 610 | name = "windows-sys" 611 | version = "0.52.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 614 | dependencies = [ 615 | "windows-targets", 616 | ] 617 | 618 | [[package]] 619 | name = "windows-targets" 620 | version = "0.52.6" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 623 | dependencies = [ 624 | "windows_aarch64_gnullvm", 625 | "windows_aarch64_msvc", 626 | "windows_i686_gnu", 627 | "windows_i686_gnullvm", 628 | "windows_i686_msvc", 629 | "windows_x86_64_gnu", 630 | "windows_x86_64_gnullvm", 631 | "windows_x86_64_msvc", 632 | ] 633 | 634 | [[package]] 635 | name = "windows_aarch64_gnullvm" 636 | version = "0.52.6" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 639 | 640 | [[package]] 641 | name = "windows_aarch64_msvc" 642 | version = "0.52.6" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 645 | 646 | [[package]] 647 | name = "windows_i686_gnu" 648 | version = "0.52.6" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 651 | 652 | [[package]] 653 | name = "windows_i686_gnullvm" 654 | version = "0.52.6" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 657 | 658 | [[package]] 659 | name = "windows_i686_msvc" 660 | version = "0.52.6" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 663 | 664 | [[package]] 665 | name = "windows_x86_64_gnu" 666 | version = "0.52.6" 667 | source = "registry+https://github.com/rust-lang/crates.io-index" 668 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 669 | 670 | [[package]] 671 | name = "windows_x86_64_gnullvm" 672 | version = "0.52.6" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 675 | 676 | [[package]] 677 | name = "windows_x86_64_msvc" 678 | version = "0.52.6" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 681 | 682 | [[package]] 683 | name = "wyz" 684 | version = "0.5.1" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 687 | dependencies = [ 688 | "tap", 689 | ] 690 | -------------------------------------------------------------------------------- /CEServer/api.cpp: -------------------------------------------------------------------------------- 1 | #include "api.h" 2 | #include "ceserver.h" 3 | #include "porthelp.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | CMemoryReaderWriter m_Driver; 14 | 15 | BOOL CApi::InitReadWriteDriver(const char *lpszDevFileName, BOOL bUseBypassSELinuxMode) { 16 | if (!lpszDevFileName) { 17 | // 驱动默认文件名 18 | lpszDevFileName = RWPROCMEM_FILE_NODE; 19 | } 20 | 21 | printf("Connecting rwDriver:%s\n", lpszDevFileName); 22 | 23 | // 连接驱动 24 | int err = 0; 25 | if (!m_Driver.ConnectDriver(lpszDevFileName, bUseBypassSELinuxMode, err)) { 26 | printf("Connect rwDriver failed. error:%d\n", err); 27 | fflush(stdout); 28 | return FALSE; 29 | } 30 | 31 | return TRUE; 32 | } 33 | 34 | BOOL GetProcessListInfo(CMemoryReaderWriter *pDriver, BOOL bGetPhyMemorySize, std::vector &vOutput) { 35 | DIR *dir = NULL; 36 | struct dirent *ptr = NULL; 37 | 38 | dir = opendir("/proc"); 39 | if (dir) { 40 | while ((ptr = readdir(dir)) != NULL) { // 循环读取路径下的每一个文件/文件夹 41 | // 如果读取到的是"."或者".."则跳过,读取到的不是文件夹名字也跳过 42 | if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) { 43 | continue; 44 | } else if (ptr->d_type != DT_DIR) { 45 | continue; 46 | } else if (strspn(ptr->d_name, "1234567890") != strlen(ptr->d_name)) { 47 | continue; 48 | } 49 | 50 | int pid = atoi(ptr->d_name); 51 | 52 | MyProcessInfo pInfo = {0}; 53 | pInfo.pid = pid; 54 | if (bGetPhyMemorySize) { 55 | uint64_t outRss, vmSize; 56 | char statm_file_path[200] = {0}; 57 | sprintf(statm_file_path, "/proc/%d/statm", pid); 58 | FILE *stat_file = fopen(statm_file_path, "r"); 59 | if (fscanf(stat_file, "%lu %lu", &vmSize, &outRss) == EOF) 60 | perror("fscanf"); 61 | pInfo.total_rss = outRss * 4; 62 | fclose(stat_file); 63 | } 64 | char cmdline[500] = {0}; 65 | char cmdline_file_path[32] = {0}; 66 | sprintf(cmdline_file_path, "/proc/%d/cmdline", pid); 67 | FILE *cmdline_file = fopen(cmdline_file_path, "r"); 68 | size_t read = fread(cmdline, 1, sizeof(cmdline), cmdline_file); 69 | if (read > 1) { 70 | for (int i = 0; i < read; i++) { 71 | if (cmdline[i] == '\0') 72 | cmdline[i] = ' '; 73 | } 74 | } 75 | fclose(cmdline_file); 76 | pInfo.cmdline = std::string(cmdline, read); 77 | vOutput.push_back(pInfo); 78 | } 79 | closedir(dir); 80 | return TRUE; 81 | } 82 | return FALSE; 83 | } 84 | 85 | HANDLE CApi::CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID) { 86 | 87 | if (dwFlags & TH32CS_SNAPPROCESS) { 88 | // printf("TH32CS_SNAPPROCESS\n"); 89 | // 获取进程列表 90 | CeProcessList *pCeProcessList = new CeProcessList(); 91 | 92 | // 获取进程列表 93 | GetProcessListInfo(&m_Driver, FALSE, pCeProcessList->vProcessList); 94 | 95 | pCeProcessList->readIter = pCeProcessList->vProcessList.begin(); 96 | return CPortHelper::CreateHandleFromPointer((uint64_t)pCeProcessList, htTHSProcess); 97 | } else if (dwFlags & TH32CS_SNAPMODULE) { 98 | // printf("TH32CS_SNAPMODULE\n"); 99 | HANDLE hm = CPortHelper::FindHandleByPID(th32ProcessID); 100 | if (!hm) { 101 | // 如果没有打开此进程,就不允许获取此进程的模块列表 102 | return 0; 103 | } 104 | 105 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)CPortHelper::GetPointerFromHandle(hm); 106 | 107 | // 取出驱动进程句柄 108 | uint64_t u64DriverProcessHandle = pCeOpenProcess->u64DriverProcessHandle; 109 | 110 | // 驱动_获取进程内存块列表(显示全部内存) 111 | std::vector vMaps; 112 | BOOL bOutListCompleted; 113 | BOOL b = m_Driver.VirtualQueryExFull(u64DriverProcessHandle, FALSE, vMaps, bOutListCompleted); 114 | 115 | if (!vMaps.size()) { 116 | printf("VirtualQueryExFull failed\n"); 117 | fflush(stdout); 118 | return 0; 119 | } 120 | 121 | CeModuleList *pCeModuleList = new CeModuleList(); 122 | 123 | // 显示进程内存块地址列表 124 | for (DRIVER_REGION_INFO rinfo : vMaps) { 125 | if (rinfo.protection == PAGE_NOACCESS) { 126 | // 此地址不可访问 127 | continue; 128 | } else if (rinfo.type == MEM_MAPPED) { 129 | continue; 130 | } else if (rinfo.name[0] == '\0') { 131 | continue; 132 | } else if (strcmp(rinfo.name, "[heap]") == 0) { 133 | continue; 134 | } 135 | if (strcmp(rinfo.name, "[vdso]") != 0) // ceOpenProcessorary patch as to not rename vdso, because it is treated differently by the ce symbol loader 136 | { 137 | for (int i = 0; rinfo.name[i]; i++) // strip square brackets from the name (conflicts with pointer notations) 138 | { 139 | if ((rinfo.name[i] == '[') || (rinfo.name[i] == ']')) { 140 | rinfo.name[i] = '_'; 141 | } 142 | } 143 | } 144 | 145 | int isExist = 0; 146 | for (auto iter = pCeModuleList->vModuleList.begin(); iter != pCeModuleList->vModuleList.end(); iter++) { 147 | if (iter->moduleName == std::string(rinfo.name)) { 148 | isExist = 1; 149 | ModuleListEntry newReplace = *iter; 150 | newReplace.moduleSize += rinfo.size; 151 | iter = pCeModuleList->vModuleList.insert(iter, newReplace); 152 | iter++; 153 | if (iter != pCeModuleList->vModuleList.end()) { 154 | pCeModuleList->vModuleList.erase(iter); 155 | 156 | break; 157 | } 158 | } 159 | } 160 | if (isExist) { 161 | continue; 162 | } 163 | 164 | uint32_t magic = 0; 165 | BOOL b = m_Driver.ReadProcessMemory(u64DriverProcessHandle, rinfo.baseaddress, &magic, 4, NULL, FALSE); 166 | if (b == FALSE) { 167 | // printf("%s is unreadable(%llx)\n", modulepath, start); 168 | continue; // unreadable 169 | } 170 | if (magic != 0x464c457f) // 7f 45 4c 46 171 | { 172 | // printf("%s is not an ELF(%llx). tempbuf=%s\n", modulepath, start, tempbuf); 173 | continue; // not an ELF 174 | } 175 | 176 | ModuleListEntry newModInfo; 177 | newModInfo.baseAddress = rinfo.baseaddress; 178 | newModInfo.moduleSize = rinfo.size; 179 | newModInfo.moduleName = rinfo.name; 180 | // printf("%s\n", newModInfo.moduleName.c_str()); 181 | 182 | pCeModuleList->vModuleList.push_back(newModInfo); 183 | 184 | // printf("+++Start:%llx,Size:%lld,Protection:%d,Type:%d,Name:%s\n", rinfo.baseaddress, rinfo.size, rinfo.protection, rinfo.type, rinfo.name); 185 | } 186 | 187 | pCeModuleList->readIter = pCeModuleList->vModuleList.begin(); 188 | return CPortHelper::CreateHandleFromPointer((uint64_t)pCeModuleList, htTHSModule); 189 | } else if (dwFlags & TH32CS_SNAPTHREAD) { 190 | int max = 64; 191 | char _taskdir[255]; 192 | DIR *taskdir; 193 | 194 | if (th32ProcessID == 0) 195 | return 0; // not handled (unlike the windows TH32CS_SNAPTHREAD, this only gets the threads of the provided processid) 196 | 197 | sprintf(_taskdir, "/proc/%d/task", th32ProcessID); 198 | 199 | taskdir = opendir(_taskdir); 200 | if (taskdir) { 201 | struct dirent *d; 202 | PThreadList tl = (PThreadList)malloc(sizeof(ThreadList)); 203 | 204 | tl->ReferenceCount = 1; 205 | tl->threadCount = 0; 206 | tl->threadList = (int *)malloc(max * sizeof(int)); 207 | 208 | d = readdir(taskdir); 209 | while (d) { 210 | int tid = atoi(d->d_name); 211 | 212 | if (tid) { 213 | tl->threadList[tl->threadCount] = tid; 214 | tl->threadCount++; 215 | if (tl->threadCount >= max) { 216 | max = max * 2; 217 | tl->threadList = (int *)realloc(tl->threadList, max * sizeof(int)); 218 | } 219 | } 220 | d = readdir(taskdir); 221 | } 222 | closedir(taskdir); 223 | 224 | return CPortHelper::CreateHandleFromPointer((uint64_t)tl, htTHSThread); 225 | } 226 | } 227 | 228 | return 0; 229 | } 230 | 231 | BOOL CApi::Process32First(HANDLE hSnapshot, ProcessListEntry &processentry) { 232 | // Get a processentry from the processlist snapshot. fill the given processentry with the data. 233 | 234 | // printf("Process32First\n"); 235 | if (CPortHelper::GetHandleType(hSnapshot) == htTHSProcess) { 236 | CeProcessList *pCeProcessList = (CeProcessList *)CPortHelper::GetPointerFromHandle(hSnapshot); 237 | pCeProcessList->readIter = pCeProcessList->vProcessList.begin(); 238 | if (pCeProcessList->readIter != pCeProcessList->vProcessList.end()) { 239 | processentry.PID = pCeProcessList->readIter->pid; 240 | processentry.ProcessName = pCeProcessList->readIter->cmdline; 241 | 242 | return TRUE; 243 | } 244 | } 245 | return FALSE; 246 | } 247 | 248 | BOOL CApi::Process32Next(HANDLE hSnapshot, ProcessListEntry &processentry) { 249 | // get the current iterator of the list and increase it. If the max has been reached, return false 250 | // printf("Process32Next\n"); 251 | 252 | if (CPortHelper::GetHandleType(hSnapshot) == htTHSProcess) { 253 | CeProcessList *pCeProcessList = (CeProcessList *)CPortHelper::GetPointerFromHandle(hSnapshot); 254 | pCeProcessList->readIter++; 255 | if (pCeProcessList->readIter != pCeProcessList->vProcessList.end()) { 256 | processentry.PID = pCeProcessList->readIter->pid; 257 | processentry.ProcessName = pCeProcessList->readIter->cmdline; 258 | return TRUE; 259 | } 260 | } 261 | return FALSE; 262 | } 263 | 264 | BOOL CApi::Module32First(HANDLE hSnapshot, ModuleListEntry &moduleentry) { 265 | if (CPortHelper::GetHandleType(hSnapshot) == htTHSModule) { 266 | CeModuleList *pCeModuleList = (CeModuleList *)CPortHelper::GetPointerFromHandle(hSnapshot); 267 | 268 | pCeModuleList->readIter = pCeModuleList->vModuleList.begin(); 269 | if (pCeModuleList->readIter != pCeModuleList->vModuleList.end()) { 270 | moduleentry.baseAddress = pCeModuleList->readIter->baseAddress; 271 | moduleentry.moduleSize = pCeModuleList->readIter->moduleSize; 272 | moduleentry.moduleName = pCeModuleList->readIter->moduleName; 273 | return TRUE; 274 | } 275 | } 276 | return FALSE; 277 | } 278 | 279 | BOOL CApi::Module32Next(HANDLE hSnapshot, ModuleListEntry &moduleentry) { 280 | // get the current iterator of the list and increase it. If the max has been reached, return false 281 | if (CPortHelper::GetHandleType(hSnapshot) == htTHSModule) { 282 | CeModuleList *pCeModuleList = (CeModuleList *)CPortHelper::GetPointerFromHandle(hSnapshot); 283 | pCeModuleList->readIter++; 284 | if (pCeModuleList->readIter != pCeModuleList->vModuleList.end()) { 285 | moduleentry.baseAddress = pCeModuleList->readIter->baseAddress; 286 | moduleentry.moduleSize = pCeModuleList->readIter->moduleSize; 287 | moduleentry.moduleName = pCeModuleList->readIter->moduleName; 288 | return TRUE; 289 | } 290 | } 291 | return FALSE; 292 | } 293 | 294 | HANDLE CApi::OpenProcess(DWORD pid) { 295 | // check if this process has already been opened 296 | HANDLE hm = CPortHelper::FindHandleByPID(pid); 297 | if (hm) { 298 | return hm; 299 | } 300 | // still here, so not opened yet 301 | 302 | // 驱动_打开进程 303 | uint64_t u64DriverProcessHandle = m_Driver.OpenProcess(pid); 304 | if (u64DriverProcessHandle == 0) { 305 | return 0; 306 | } 307 | CeOpenProcess *pCeOpenProcess = new CeOpenProcess(); 308 | pCeOpenProcess->pid = pid; 309 | pCeOpenProcess->u64DriverProcessHandle = u64DriverProcessHandle; 310 | pCeOpenProcess->nLastGetMapsTime = 0; 311 | return CPortHelper::CreateHandleFromPointer((uint64_t)pCeOpenProcess, htProcesHandle); 312 | } 313 | 314 | void CApi::CloseHandle(HANDLE h) { 315 | 316 | int i; 317 | handleType ht = CPortHelper::GetHandleType(h); 318 | uint64_t pl = CPortHelper::GetPointerFromHandle(h); 319 | 320 | if (ht == htTHSModule) { 321 | auto pCeModuleList = (CeModuleList *)pl; 322 | delete pCeModuleList; 323 | } else if (ht == htTHSProcess) { 324 | auto pProcessList = (CeProcessList *)pl; 325 | delete pProcessList; 326 | } else if (ht == htProcesHandle) { 327 | auto pOpenProcess = (CeOpenProcess *)pl; 328 | m_Driver.CloseHandle(pOpenProcess->u64DriverProcessHandle); 329 | delete pOpenProcess; 330 | } else if (ht == htTHSThread) { 331 | auto pThreadList = (PThreadList)pl; 332 | free(pThreadList->threadList); 333 | free(pThreadList); 334 | } 335 | // else 336 | //{ 337 | // if (ht == htNativeThreadHandle) 338 | // { 339 | // uint64_t *th = GetPointerFromHandle(h); 340 | // printf("Closing thread handle\n"); 341 | 342 | // free(th); 343 | // RemoveHandle(h); 344 | // } 345 | // else 346 | // { 347 | // RemoveHandle(h); //no idea what it is... 348 | // } 349 | 350 | //} 351 | CPortHelper::RemoveHandle(h); 352 | } 353 | 354 | int CApi::VirtualQueryExFull(HANDLE hProcess, uint32_t flags, std::vector &vRinfo) 355 | /* 356 | * creates a full list of the maps file (less seeking) 357 | */ 358 | { 359 | printf("VirtualQueryExFull: %d \n", hProcess); 360 | 361 | if (CPortHelper::GetHandleType(hProcess) != htProcesHandle) { 362 | printf("VirtualQueryExFull handle Error: %d \n", hProcess); 363 | return 0; 364 | } 365 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)CPortHelper::GetPointerFromHandle(hProcess); 366 | 367 | // 取出驱动进程句柄 368 | uint64_t u64DriverProcessHandle = pCeOpenProcess->u64DriverProcessHandle; 369 | 370 | // int pagedonly = flags & VQE_PAGEDONLY; 371 | // int dirtyonly = flags & VQE_DIRTYONLY; 372 | int noshared = flags & VQE_NOSHARED; 373 | 374 | vRinfo.clear(); 375 | 376 | // 驱动_获取进程内存块列表(只显示在物理内存中的内存) 377 | std::lock_guard mtxLock(pCeOpenProcess->mtxLockLastMaps); 378 | pCeOpenProcess->vLastMaps.clear(); 379 | BOOL bOutListCompleted; 380 | m_Driver.VirtualQueryExFull(u64DriverProcessHandle, TRUE, pCeOpenProcess->vLastMaps, bOutListCompleted); 381 | printf("m_Driver.VirtualQueryExFull(showPhy) :%zu\n", pCeOpenProcess->vLastMaps.size()); 382 | fflush(stdout); 383 | 384 | if (!pCeOpenProcess->vLastMaps.size()) { 385 | pCeOpenProcess->nLastGetMapsTime = 0; 386 | 387 | printf("m_Driver.VirtualQueryExFull(showPhy) failed.\n"); 388 | fflush(stdout); 389 | 390 | return 0; 391 | } else { 392 | // 记录当前系统运行毫秒 393 | struct timespec times = {0, 0}; 394 | clock_gettime(CLOCK_MONOTONIC, ×); 395 | pCeOpenProcess->nLastGetMapsTime = times.tv_sec * 1000 + times.tv_nsec / 1000000; 396 | } 397 | 398 | // 显示进程内存块地址列表 399 | for (DRIVER_REGION_INFO rinfo : pCeOpenProcess->vLastMaps) { 400 | if (rinfo.protection == PAGE_NOACCESS) { 401 | // 此地址不可访问 402 | continue; 403 | } else if (rinfo.type == MEM_MAPPED) // some checks to see if it passed 404 | { 405 | if (noshared) { 406 | continue; 407 | } 408 | } 409 | 410 | RegionInfo newInfo = {0}; 411 | newInfo.baseaddress = rinfo.baseaddress; 412 | newInfo.size = rinfo.size; 413 | newInfo.protection = rinfo.protection; 414 | newInfo.type = rinfo.type; 415 | vRinfo.push_back(newInfo); 416 | // printf("+++Start:%llx,Size:%lld,Protection:%d,Type:%d,Name:%s\n", rinfo.baseaddress, rinfo.size, rinfo.protection, rinfo.type, rinfo.name); 417 | } 418 | return 1; 419 | } 420 | 421 | int CApi::VirtualQueryEx(HANDLE hProcess, uint64_t lpAddress, RegionInfo &rinfo, std::string &memName) { 422 | /* 423 | * Alternate method: read pagemaps and look up the pfn in /proc/kpageflags (needs to 2 files open and random seeks through both files, so not sure if slow or painfully slow...) 424 | */ 425 | 426 | // VirtualQueryEx stub port. Not a real port, and returns true if successful and false on error 427 | int found = 0; 428 | 429 | // printf("VirtualQueryEx %d (%p)\n", hProcess, lpAddress); 430 | 431 | if (CPortHelper::GetHandleType(hProcess) != htProcesHandle) { 432 | return 0; 433 | } 434 | 435 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)CPortHelper::GetPointerFromHandle(hProcess); 436 | 437 | // 取出驱动进程句柄 438 | uint64_t u64DriverProcessHandle = pCeOpenProcess->u64DriverProcessHandle; 439 | 440 | // 驱动_获取进程内存块列表(只显示在物理内存中的内存) 441 | std::lock_guard mtxLock(pCeOpenProcess->mtxLockLastMaps); 442 | 443 | // 记录当前系统运行毫秒 444 | struct timespec times = {0, 0}; 445 | clock_gettime(CLOCK_MONOTONIC, ×); 446 | auto nowTime = times.tv_sec * 1000 + times.tv_nsec / 1000000; 447 | if ((nowTime - pCeOpenProcess->nLastGetMapsTime) > 1000 * 60) // 每60秒获取一次内存列表 448 | { 449 | // 上次的列表超时了,重新获取一份新的 450 | pCeOpenProcess->vLastMaps.clear(); 451 | BOOL bOutListCompleted; 452 | BOOL b = m_Driver.VirtualQueryExFull(u64DriverProcessHandle, TRUE, pCeOpenProcess->vLastMaps, bOutListCompleted); 453 | fflush(stdout); 454 | 455 | if (!pCeOpenProcess->vLastMaps.size()) { 456 | pCeOpenProcess->nLastGetMapsTime = 0; 457 | printf("VirtualQueryExFull failed\n"); 458 | fflush(stdout); 459 | return 0; 460 | } else { 461 | // 记录这次列表的获取时间 462 | memset(×, 0, sizeof(times)); 463 | clock_gettime(CLOCK_MONOTONIC, ×); 464 | pCeOpenProcess->nLastGetMapsTime = times.tv_sec * 1000 + times.tv_nsec / 1000000; 465 | } 466 | } 467 | 468 | rinfo.protection = 0; 469 | rinfo.baseaddress = (uint64_t)lpAddress & ~0xfff; 470 | lpAddress = (uint64_t)(rinfo.baseaddress); 471 | 472 | // 显示进程内存块地址列表 473 | for (DRIVER_REGION_INFO r : pCeOpenProcess->vLastMaps) { 474 | uint64_t stop = r.baseaddress + r.size; 475 | if (stop > lpAddress) // we passed it 476 | { 477 | found = 1; 478 | 479 | if (lpAddress >= r.baseaddress) { 480 | // it's inside the region, so useable 481 | 482 | rinfo.protection = r.protection; 483 | rinfo.type = r.type; 484 | rinfo.size = stop - rinfo.baseaddress; 485 | } else { 486 | rinfo.size = r.baseaddress - rinfo.baseaddress; 487 | rinfo.protection = PAGE_NOACCESS; 488 | rinfo.type = 0; 489 | } 490 | memName = r.name; 491 | 492 | // printf("+++Start:%llx,Size:%lld %lld,Protection:%d,Type:%d\n", rinfo.baseaddress, rinfo.size, r.size, rinfo.protection, rinfo.type); 493 | break; 494 | } 495 | } 496 | 497 | return found; 498 | } 499 | 500 | int CApi::ReadProcessMemory(HANDLE hProcess, void *lpAddress, void *buffer, int size) { 501 | // idea in case this is too slow. always read a full page and keep the last 16 accessed pages. 502 | // only on cache miss, or if the cache is older than 1000 milliseconds fetch the page. 503 | // keep in mind that this routine can get called by multiple threads at the same time 504 | 505 | // todo: Try process_vm_readv 506 | 507 | // printf("ReadProcessMemory(%d, %p, %p, %d)\n", (int)hProcess, lpAddress, buffer, size); 508 | 509 | // printf("ReadProcessMemory\n"); 510 | 511 | size_t bread = 0; 512 | 513 | if (CPortHelper::GetHandleType(hProcess) != htProcesHandle) { 514 | return 0; 515 | } 516 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)CPortHelper::GetPointerFromHandle(hProcess); 517 | 518 | // 取出驱动进程句柄 519 | uint64_t u64DriverProcessHandle = pCeOpenProcess->u64DriverProcessHandle; 520 | 521 | // valid handle 522 | // 驱动_读取进程内存 523 | m_Driver.ReadProcessMemory(u64DriverProcessHandle, (uint64_t)lpAddress, buffer, size, &bread, FALSE); 524 | return (int)bread; 525 | } 526 | 527 | int CApi::WriteProcessMemory(HANDLE hProcess, void *lpAddress, void *buffer, int size) { 528 | size_t written = 0; 529 | // printf("WriteProcessMemory(%d, %p, %p, %d\n", hProcess, lpAddress, buffer, size); 530 | 531 | if (CPortHelper::GetHandleType(hProcess) != htProcesHandle) { 532 | return 0; 533 | } 534 | 535 | CeOpenProcess *pCeOpenProcess = (CeOpenProcess *)CPortHelper::GetPointerFromHandle(hProcess); 536 | 537 | // 取出驱动进程句柄 538 | uint64_t u64DriverProcessHandle = pCeOpenProcess->u64DriverProcessHandle; 539 | 540 | // valid handle 541 | // 驱动_读取进程内存 542 | m_Driver.WriteProcessMemory(u64DriverProcessHandle, (uint64_t)lpAddress, buffer, size, &written, FALSE); 543 | 544 | return (int)written; 545 | } 546 | -------------------------------------------------------------------------------- /CEServer/symbols.cpp: -------------------------------------------------------------------------------- 1 | #include "symbols.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma pack(1) 14 | typedef struct { 15 | uint64_t address; 16 | int size; 17 | int type; 18 | unsigned char namelength; 19 | char name[0]; 20 | } symbolinfo, *psymbolinfo; 21 | #pragma pack() 22 | 23 | #define TEMPBUFSIZE 64*1024 24 | // 25 | // 26 | //void loadStringTable64(int f, Elf64_Shdr *sectionHeaders, unsigned char **stringTable, int index) 27 | //{ 28 | // if ((stringTable[index]==NULL) && (sectionHeaders[index].sh_type==SHT_STRTAB)) 29 | // { 30 | // stringTable[index]=malloc(sectionHeaders[index].sh_size); 31 | // if (pread(f, stringTable[index], sectionHeaders[index].sh_size, sectionHeaders[index].sh_offset)==-1) 32 | // { 33 | // debug_log("Failure loading the stringtable\n"); 34 | // free(stringTable[index]); 35 | // stringTable[index]=NULL; 36 | // } 37 | // 38 | // } 39 | // else 40 | // debug_log("Not a string table\n"); 41 | //} 42 | // 43 | //void loadStringTable32(int f, Elf32_Shdr *sectionHeaders, unsigned char **stringTable, int index) 44 | //{ 45 | // if ((stringTable[index]==NULL) && (sectionHeaders[index].sh_type==SHT_STRTAB)) 46 | // { 47 | // stringTable[index]=malloc(sectionHeaders[index].sh_size); 48 | // if (pread(f, stringTable[index], sectionHeaders[index].sh_size, sectionHeaders[index].sh_offset)==-1) 49 | // { 50 | // debug_log("Failure loading the stringtable\n"); 51 | // free(stringTable[index]); 52 | // stringTable[index]=NULL; 53 | // } 54 | // 55 | // } 56 | // else 57 | // debug_log("Not a string table\n"); 58 | //} 59 | // 60 | //int ELF32(int f, Elf32_Ehdr *b, unsigned char **output) 61 | ///* 62 | //Caller must free output manually 63 | //*/ 64 | //{ 65 | // int i,j; 66 | // 67 | // unsigned char *tempbuffer=NULL; 68 | // int tempbufferpos=0; 69 | // int maxoutputsize=TEMPBUFSIZE; 70 | // tempbuffer=malloc(TEMPBUFSIZE); 71 | // 72 | // //setup zlib 73 | // z_stream strm; 74 | // strm.zalloc = Z_NULL; 75 | // strm.zfree = Z_NULL; 76 | // strm.opaque = Z_NULL; 77 | // deflateInit(&strm, 9); 78 | // 79 | // *output=malloc(maxoutputsize); //allocate 256KB. This "should" be enough, but reallocate if more is needed 80 | // 81 | // strm.avail_out=maxoutputsize-3*sizeof(uint32_t); //first if it's an exe, followed by the compressed size, followed by the decompressed size 82 | // strm.next_out=(unsigned char *)&(*output)[sizeof(uint32_t)*3]; 83 | // 84 | // *(uint32_t *)(&(*output)[0])=(b->e_type==ET_EXEC); 85 | // 86 | ///* 87 | // 88 | // debug_log("e_shoff=%x\n", b->e_shoff); 89 | // debug_log("e_shentsize=%d\n", b->e_shentsize); 90 | // debug_log("e_shnum=%d\n", b->e_shnum); 91 | // debug_log("e_shstrndx=%d\n", b->e_shstrndx);*/ 92 | // 93 | // Elf32_Shdr *sectionHeaders=malloc(b->e_shentsize*b->e_shnum); 94 | // 95 | // if (pread(f, sectionHeaders, b->e_shentsize*b->e_shnum, b->e_shoff)==-1) 96 | // { 97 | // //printf("Failure to read sectionHeaders\n"); 98 | // deflateEnd(&strm); 99 | // if (sectionHeaders) 100 | // free(sectionHeaders); 101 | // 102 | // if (output) 103 | // free(output); 104 | // 105 | // if (tempbuffer) 106 | // free(tempbuffer); 107 | // 108 | // return -1; 109 | // } 110 | // 111 | // unsigned char **stringTable=calloc(b->e_shnum, sizeof(unsigned char*) ); 112 | // 113 | // loadStringTable32(f, sectionHeaders, stringTable, b->e_shstrndx); 114 | // 115 | // 116 | // for (i=0; ie_shnum; i++) 117 | // { 118 | // //printf("Section %d (%x): name=%s\n", i, sectionHeaders[i].sh_addr, &stringTable[b->e_shstrndx][sectionHeaders[i].sh_name]); 119 | // 120 | // if ((sectionHeaders[i].sh_type==SHT_SYMTAB) || (sectionHeaders[i].sh_type==SHT_DYNSYM)) 121 | // { 122 | // // debug_log("Symbol data:\n", i); 123 | // 124 | // // debug_log("sh_addr=%x\n", sectionHeaders[i].sh_addr); 125 | // //printf("sh_offset=%x\n", sectionHeaders[i].sh_offset); 126 | // //printf("sh_size=%x\n", sectionHeaders[i].sh_size); 127 | // //printf("sh_link=%d (string table)\n", sectionHeaders[i].sh_link); 128 | // //printf("sh_info=%d\n", sectionHeaders[i].sh_info); 129 | // 130 | // Elf32_Sym *symbolTable=malloc(sectionHeaders[i].sh_size); 131 | // if (pread(f, symbolTable, sectionHeaders[i].sh_size, sectionHeaders[i].sh_offset)==-1) 132 | // { 133 | // // debug_log("Failure reading symbol table\n"); 134 | // return -1; 135 | // } 136 | // int maxindex=sectionHeaders[i].sh_size / sizeof(Elf32_Sym); 137 | // 138 | // loadStringTable32(f, sectionHeaders, stringTable, sectionHeaders[i].sh_link); 139 | // 140 | // //printf("maxindex=%d\n", maxindex); 141 | // for (j=0; j=TEMPBUFSIZE) 160 | // { 161 | // //compress the current temp buffer 162 | // //printf("compressing\n"); 163 | // strm.avail_in=tempbufferpos; 164 | // strm.next_in=tempbuffer; 165 | // 166 | // while (strm.avail_in) 167 | // { 168 | // if (deflate(&strm, Z_NO_FLUSH)!=Z_OK) 169 | // { 170 | // //printf("FAILURE TO COMPRESS!\n"); 171 | // return -1; 172 | // } 173 | // //printf("strm.avail_out=%d\n", strm.avail_out); 174 | // 175 | // if (strm.avail_out==0) 176 | // { 177 | // 178 | // 179 | // //printf("Out buffer full. Reallocating\n"); 180 | // *output=realloc(*output, maxoutputsize*2); 181 | // 182 | // strm.next_out=(unsigned char *)&(*output)[maxoutputsize]; 183 | // strm.avail_out=maxoutputsize; 184 | // maxoutputsize=maxoutputsize*2; 185 | // 186 | // 187 | // } 188 | // 189 | // } 190 | // tempbufferpos=0; 191 | // } 192 | // 193 | // 194 | // 195 | // psymbolinfo si=(psymbolinfo)&tempbuffer[tempbufferpos]; 196 | // si->address=symbolTable[j].st_value; 197 | // si->size=symbolTable[j].st_size; 198 | // si->type=symbolTable[j].st_info; 199 | // si->namelength=namelength; 200 | // memcpy(&si->name, symbolname, namelength); 201 | // 202 | // 203 | // tempbufferpos+=entrysize; 204 | // } 205 | // } 206 | // 207 | // free(symbolTable); 208 | // 209 | // } 210 | // 211 | // } 212 | // 213 | // for (i=0; ie_shnum; i++) 214 | // { 215 | // if (stringTable[i]) 216 | // free(stringTable[i]); 217 | // } 218 | // free(stringTable); 219 | // 220 | // free(sectionHeaders); 221 | // 222 | // 223 | // debug_log("end:\n"); 224 | // strm.avail_in=tempbufferpos; 225 | // strm.next_in=tempbuffer; 226 | // 227 | // while (1) 228 | // { 229 | // 230 | // i=deflate(&strm, Z_FINISH); 231 | // debug_log("i=%d\n", i); 232 | // if (i==Z_STREAM_END) //done 233 | // break; 234 | // 235 | // if (i!=Z_OK) 236 | // { 237 | // debug_log("Failure to compress: %i\n", i); 238 | // return -1; 239 | // } 240 | // 241 | // if (strm.avail_out==0) 242 | // { 243 | // debug_log("Out buffer full. Reallocating :%d\n", maxoutputsize*2); 244 | // *output=realloc(*output, maxoutputsize*2); 245 | // 246 | // strm.next_out=(unsigned char *)&(*output)[maxoutputsize]; 247 | // strm.avail_out=maxoutputsize; 248 | // maxoutputsize=maxoutputsize*2; 249 | // 250 | // } 251 | // else 252 | // break; 253 | // 254 | // }; 255 | // 256 | // /*printf("strm.avail_out=%d\n", strm.avail_out); 257 | // 258 | // debug_log("total_in = %lu\n", strm.total_in); 259 | // debug_log("total_out = %lu\n", strm.total_out);*/ 260 | // 261 | // deflateEnd(&strm); 262 | // 263 | // 264 | // //update the size 265 | // *(uint32_t *)(&(*output)[4])=strm.total_out+3*sizeof(uint32_t); 266 | // *(uint32_t *)(&(*output)[8])=strm.total_in; 267 | // 268 | // free(tempbuffer); 269 | // 270 | // return 0; 271 | //} 272 | // 273 | //int ELF64(int f, Elf64_Ehdr *b, unsigned char **output) 274 | ///* 275 | //Caller must free output manually 276 | //*/ 277 | //{ 278 | // int i,j; 279 | // 280 | // 281 | // unsigned char *tempbuffer=NULL; 282 | // int tempbufferpos=0; 283 | // int maxoutputsize=TEMPBUFSIZE; 284 | // tempbuffer=malloc(TEMPBUFSIZE); 285 | // 286 | // //setup zlib 287 | // z_stream strm; 288 | // strm.zalloc = Z_NULL; 289 | // strm.zfree = Z_NULL; 290 | // strm.opaque = Z_NULL; 291 | // deflateInit(&strm, 9); 292 | // 293 | // *output=malloc(maxoutputsize); //allocate 256KB. This "should" be enough, but reallocate if more is needed 294 | // 295 | // strm.avail_out=maxoutputsize-3*sizeof(uint32_t); //the first 8 bytes will contain the compressed and uncompressed size 296 | // strm.next_out=(unsigned char *)&(*output)[sizeof(uint32_t)*3]; 297 | // 298 | // *(uint32_t *)(&(*output)[0])=(b->e_type==ET_EXEC); 299 | ///* 300 | // 301 | // debug_log("e_shoff=%lx\n", b->e_shoff); 302 | // debug_log("e_shentsize=%d\n", b->e_shentsize); 303 | // debug_log("e_shnum=%d\n", b->e_shnum); 304 | // debug_log("e_shstrndx=%d\n", b->e_shstrndx);*/ 305 | // 306 | // Elf64_Shdr *sectionHeaders=malloc(b->e_shentsize*b->e_shnum); 307 | // 308 | // if (pread(f, sectionHeaders, b->e_shentsize*b->e_shnum, b->e_shoff)==-1) 309 | // { 310 | // //printf("Failure to read sectionHeaders\n"); 311 | // deflateEnd(&strm); 312 | // if (sectionHeaders) 313 | // free(sectionHeaders); 314 | // 315 | // if (output) 316 | // free(output); 317 | // 318 | // if (tempbuffer) 319 | // free(tempbuffer); 320 | // 321 | // return -1; 322 | // } 323 | // 324 | // unsigned char **stringTable=calloc(b->e_shnum, sizeof(unsigned char*) ); 325 | // 326 | // loadStringTable64(f, sectionHeaders, stringTable, b->e_shstrndx); 327 | // 328 | // 329 | // for (i=0; ie_shnum; i++) 330 | // { 331 | // // debug_log("Section %d (%lx): name=%s\n", i, sectionHeaders[i].sh_addr, &stringTable[b->e_shstrndx][sectionHeaders[i].sh_name]); 332 | // 333 | // if ((sectionHeaders[i].sh_type==SHT_SYMTAB) || (sectionHeaders[i].sh_type==SHT_DYNSYM)) 334 | // {/* 335 | // debug_log("Symbol data:\n", i); 336 | // 337 | // debug_log("sh_addr=%lx\n", sectionHeaders[i].sh_addr); 338 | // debug_log("sh_offset=%lx\n", sectionHeaders[i].sh_offset); 339 | // debug_log("sh_size=%ld\n", sectionHeaders[i].sh_size); 340 | // debug_log("sh_link=%d (string table)\n", sectionHeaders[i].sh_link); 341 | // debug_log("sh_info=%d\n", sectionHeaders[i].sh_info);*/ 342 | // 343 | // Elf64_Sym *symbolTable=malloc(sectionHeaders[i].sh_size); 344 | // if (pread(f, symbolTable, sectionHeaders[i].sh_size, sectionHeaders[i].sh_offset)==-1) 345 | // { 346 | // //printf("Failure reading symbol table\n"); 347 | // return -1; 348 | // } 349 | // int maxindex=sectionHeaders[i].sh_size / sizeof(Elf64_Sym); 350 | // 351 | // loadStringTable64(f, sectionHeaders, stringTable, sectionHeaders[i].sh_link); 352 | // 353 | // //printf("maxindex=%d\n", maxindex); 354 | // for (j=0; j=TEMPBUFSIZE) 374 | // { 375 | // //compress the current temp buffer 376 | // //printf("compressing\n"); 377 | // strm.avail_in=tempbufferpos; 378 | // strm.next_in=tempbuffer; 379 | // 380 | // while (strm.avail_in) 381 | // { 382 | // if (deflate(&strm, Z_NO_FLUSH)!=Z_OK) 383 | // { 384 | // debug_log("FAILURE TO COMPRESS!\n"); 385 | // return -1; 386 | // } 387 | // //printf("strm.avail_out=%d\n", strm.avail_out); 388 | // 389 | // if (strm.avail_out==0) 390 | // { 391 | // 392 | // // debug_log("Out buffer full. Reallocating\n"); 393 | // *output=realloc(*output, maxoutputsize*2); 394 | // 395 | // strm.next_out=(unsigned char *)&(*output)[maxoutputsize]; 396 | // strm.avail_out=maxoutputsize; 397 | // maxoutputsize=maxoutputsize*2; 398 | // } 399 | // 400 | // } 401 | // tempbufferpos=0; 402 | // } 403 | // 404 | // 405 | // 406 | // psymbolinfo si=(psymbolinfo)&tempbuffer[tempbufferpos]; 407 | // si->address=symbolTable[j].st_value; 408 | // si->size=symbolTable[j].st_size; 409 | // si->type=symbolTable[j].st_info; 410 | // si->namelength=namelength; 411 | // memcpy(&si->name, symbolname, namelength); 412 | // 413 | // 414 | // tempbufferpos+=entrysize; 415 | // } 416 | // } 417 | // 418 | // free(symbolTable); 419 | // 420 | // } 421 | // 422 | // } 423 | // 424 | // for (i=0; ie_shnum; i++) 425 | // { 426 | // if (stringTable[i]) 427 | // free(stringTable[i]); 428 | // } 429 | // free(stringTable); 430 | // 431 | // free(sectionHeaders); 432 | // 433 | // 434 | // debug_log("end:\n"); 435 | // strm.avail_in=tempbufferpos; 436 | // strm.next_in=tempbuffer; 437 | // 438 | // while (1) 439 | // { 440 | // 441 | // i=deflate(&strm, Z_FINISH); 442 | // debug_log("i=%d\n", i); 443 | // if (i==Z_STREAM_END) //done 444 | // break; 445 | // 446 | // if (i!=Z_OK) 447 | // { 448 | // debug_log("Failure to compress: %i\n", i); 449 | // return -1; 450 | // } 451 | // 452 | // if (strm.avail_out==0) 453 | // { 454 | // debug_log("Out buffer full. Reallocating :%d\n", maxoutputsize*2); 455 | // *output=realloc(*output, maxoutputsize*2); 456 | // 457 | // strm.next_out=(unsigned char *)&(*output)[maxoutputsize]; 458 | // strm.avail_out=maxoutputsize; 459 | // maxoutputsize=maxoutputsize*2; 460 | // } 461 | // else 462 | // break; 463 | // 464 | // }; 465 | // 466 | // debug_log("strm.avail_out=%d\n", strm.avail_out); 467 | // 468 | // debug_log("total_in = %lu\n", strm.total_in); 469 | // debug_log("total_out = %lu\n", strm.total_out); 470 | // 471 | // deflateEnd(&strm); 472 | // 473 | // 474 | // *(uint32_t *)(&(*output)[4])=strm.total_out+3*sizeof(uint32_t); 475 | // *(uint32_t *)(&(*output)[8])=strm.total_in; 476 | // 477 | // 478 | // free(tempbuffer); 479 | // 480 | // return 0; //still alive 481 | // 482 | //} 483 | // 484 | //int GetSymbolListFromFile(char *filename, unsigned char **output, int *outputsize) 485 | ///* 486 | // * Returns a pointer to a compressed stream. The caller needs to free it 487 | // */ 488 | //{ 489 | // int i, f; 490 | // unsigned char *b=NULL; 491 | // 492 | // debug_log("GetSymbolListFromFile(%s)\n", filename); 493 | // 494 | // *output=NULL; 495 | // f=open(filename, O_RDONLY); 496 | // if (f==-1) 497 | // return -1; 498 | // 499 | // b=malloc(sizeof(Elf64_Ehdr)); 500 | // if (b) 501 | // { 502 | // i=pread(f, b, sizeof(Elf64_Ehdr), 0); 503 | // 504 | // if (*(uint32_t *)b!=0x464c457f) 505 | // return -1; //not an ELF file 506 | // 507 | // if (b[EI_CLASS]==ELFCLASS32) 508 | // i=ELF32(f, (Elf32_Ehdr *)b, output); 509 | // else 510 | // i=ELF64(f, (Elf64_Ehdr *)b, output); 511 | // 512 | // free(b); 513 | // } 514 | // 515 | // close(f); 516 | // 517 | // return i; 518 | //} 519 | // 520 | // 521 | //int GetModuleSize32(int f, Elf32_Ehdr *b) 522 | //{ 523 | // /* debug_log("32 bit\n"); 524 | // debug_log("b->e_ehsize=%d (%d)\n", (int)b->e_ehsize, (int)sizeof(Elf32_Ehdr));*/ 525 | // 526 | // //Elf32_Shdr *sectionHeaders=malloc(b->e_shentsize*b->e_shnum); 527 | // Elf32_Phdr *programHeaders=malloc(b->e_phentsize*b->e_phnum); 528 | ///* debug_log("e_shoff=%x\n", b->e_shoff); 529 | // debug_log("e_shentsize=%d\n", b->e_shentsize); 530 | // debug_log("e_shnum=%d\n", b->e_shnum); 531 | // debug_log("e_shstrndx=%d\n", b->e_shstrndx); 532 | // 533 | // debug_log("e_phoff=%x\n", b->e_phoff); 534 | // debug_log("e_phentsize=%d\n", b->e_phentsize); 535 | // debug_log("e_phnum=%d\n", b->e_phnum); */ 536 | // 537 | // if (pread(f, programHeaders, b->e_phentsize*b->e_phnum, b->e_phoff)==-1) 538 | // { 539 | // if (programHeaders) 540 | // free(programHeaders); 541 | // 542 | // return 0; 543 | // } 544 | // 545 | // 546 | // int i; 547 | // unsigned long long lowest=0;//programHeaders[0].p_vaddr; 548 | // unsigned long long highest=0;//programHeaders[0].p_vaddr+programHeaders[0].p_memsz; 549 | // 550 | // for (i=0; ie_phnum; i++) 551 | // { 552 | // if (programHeaders[i].p_memsz>0) 553 | // { 554 | // if ((i==0) || (programHeaders[i].p_vaddrhighest)) 558 | // highest=programHeaders[i].p_vaddr+programHeaders[i].p_memsz; 559 | // 560 | // 561 | ///* 562 | // debug_log("%d: %x\n", i, programHeaders[i].p_type); 563 | // debug_log("Virtual Address: %llx-%llx:\n", (long long unsigned int)programHeaders[i].p_vaddr,(long long unsigned int)programHeaders[i].p_vaddr+(long long unsigned int)programHeaders[i].p_memsz); 564 | // debug_log("Size: %d (%x)\n", (int)programHeaders[i].p_memsz, (int)programHeaders[i].p_memsz); 565 | // */ 566 | // } 567 | // } 568 | // 569 | // if (programHeaders) 570 | // free(programHeaders); 571 | // 572 | // // debug_log("lowest=%llx highest=%llx\n", lowest, highest); 573 | // // debug_log("size=%llx\n", highest-lowest); 574 | // return highest-lowest; 575 | //} 576 | // 577 | //int GetModuleSize64(int f, Elf64_Ehdr *b) 578 | //{ 579 | // /*printf("64 bit\n"); 580 | // debug_log("b->e_ehsize=%d (%d)\n", (int)b->e_ehsize, (int)sizeof(Elf32_Ehdr));*/ 581 | // 582 | // Elf64_Phdr *programHeaders=malloc(b->e_phentsize*b->e_phnum); 583 | ///* debug_log("e_shoff=%x\n", (int)b->e_shoff); 584 | // debug_log("e_shentsize=%d\n", b->e_shentsize); 585 | // debug_log("e_shnum=%d\n", b->e_shnum); 586 | // debug_log("e_shstrndx=%d\n", b->e_shstrndx); 587 | // 588 | // debug_log("e_phoff=%x\n", (int)b->e_phoff); 589 | // debug_log("e_phentsize=%d\n", b->e_phentsize); 590 | // debug_log("e_phnum=%d\n", b->e_phnum); 591 | // */ 592 | // 593 | // if (pread(f, programHeaders, b->e_phentsize*b->e_phnum, b->e_phoff)==-1) 594 | // { 595 | // if (programHeaders) 596 | // free(programHeaders); 597 | // 598 | // return 0; 599 | // } 600 | // 601 | // 602 | // int i; 603 | // unsigned long long lowest=0;//programHeaders[0].p_vaddr; 604 | // unsigned long long highest=0;//programHeaders[0].p_vaddr+programHeaders[0].p_memsz; 605 | // 606 | // for (i=0; ie_phnum; i++) 607 | // { 608 | // if (programHeaders[i].p_memsz>0) 609 | // { 610 | // if ((i==0) || (programHeaders[i].p_vaddrhighest)) 614 | // highest=programHeaders[i].p_vaddr+programHeaders[i].p_memsz; 615 | // 616 | // 617 | ///* 618 | // debug_log("%d: %x\n", i, programHeaders[i].p_type); 619 | // debug_log("Virtual Address: %llx-%llx:\n", (long long unsigned int)programHeaders[i].p_vaddr,(long long unsigned int)programHeaders[i].p_vaddr+(long long unsigned int)programHeaders[i].p_memsz); 620 | // debug_log("Size: %d (%x)\n", (int)programHeaders[i].p_memsz, (int)programHeaders[i].p_memsz); 621 | // */ 622 | // } 623 | // } 624 | // 625 | // if (programHeaders) 626 | // free(programHeaders); 627 | // 628 | // // debug_log("lowest=%llx highest=%llx\n", lowest, highest); 629 | // // debug_log("size=%llx\n", highest-lowest); 630 | // return highest-lowest; 631 | //} 632 | // 633 | // 634 | //unsigned long long GetModuleSize(char *filename, unsigned long long defaultsize) 635 | ///* 636 | // * Returns size the module will take in memory 637 | // */ 638 | //{ 639 | // int i,f; 640 | // unsigned char *b=NULL; 641 | // int result=defaultsize; 642 | // 643 | //// debug_log("GetModuleSize(\"%s\")=",filename); 644 | // 645 | // f=open(filename, O_RDONLY); 646 | // if (f==-1) 647 | // { 648 | // debug_log("Failed to open %s\n", filename); 649 | // return defaultsize; 650 | // } 651 | // else 652 | // { 653 | // b=malloc(sizeof(Elf64_Ehdr)); 654 | // if (b) 655 | // { 656 | // i=pread(f, b, sizeof(Elf64_Ehdr), 0); 657 | // 658 | // if (*(uint32_t *)b!=0x464c457f) 659 | // { 660 | // debug_log("%s is not an elf\n", filename); 661 | // free(b); 662 | // close(f); 663 | // return defaultsize; //not an ELF file 664 | // } 665 | // 666 | // if (b[EI_CLASS]==ELFCLASS32) 667 | // i=GetModuleSize32(f, (Elf32_Ehdr *)b); 668 | // else 669 | // i=GetModuleSize64(f, (Elf64_Ehdr *)b); 670 | // 671 | // free(b); 672 | // close(f); 673 | // 674 | // //printf("%x\n",i); 675 | // return i; 676 | // } 677 | // else 678 | // { 679 | // close(f); 680 | // return defaultsize; 681 | // } 682 | // 683 | // 684 | // 685 | // } 686 | // 687 | // 688 | //} 689 | -------------------------------------------------------------------------------- /CEServer/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "api.h" 3 | #include "ceserver.h" 4 | #include "context.h" 5 | #include "native-api.h" 6 | #include "porthelp.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define PORT 3168 27 | 28 | char versionstring[] = "CHEATENGINE Network 2.3"; 29 | ssize_t recvall(int s, void *buf, size_t size, int flags) { 30 | ssize_t totalreceived = 0; 31 | ssize_t sizeleft = size; 32 | unsigned char *buffer = (unsigned char *)buf; 33 | 34 | // enter recvall 35 | flags = flags | MSG_WAITALL; 36 | 37 | while (sizeleft > 0) { 38 | ssize_t i = recv(s, &buffer[totalreceived], sizeleft, flags); 39 | if (i == 0) { 40 | printf("recv returned 0\n"); 41 | return i; 42 | } 43 | if (i == -1) { 44 | printf("recv returned -1\n"); 45 | if (errno == EINTR) { 46 | printf("errno = EINTR\n"); 47 | i = 0; 48 | } else { 49 | printf("Error during recvall: %d. errno=%d\n", (int)i, errno); 50 | return i; // read error, or disconnected 51 | } 52 | } 53 | totalreceived += i; 54 | sizeleft -= i; 55 | } 56 | // leave recvall 57 | return totalreceived; 58 | } 59 | 60 | ssize_t sendall(int s, void *buf, size_t size, int flags) { 61 | ssize_t totalsent = 0; 62 | ssize_t sizeleft = size; 63 | unsigned char *buffer = (unsigned char *)buf; 64 | 65 | // debug print 66 | // printf("send: "); 67 | // for(int i=0; i 0) { 72 | ssize_t i = send(s, &buffer[totalsent], sizeleft, flags); 73 | 74 | if (i == 0) { 75 | return i; 76 | } 77 | 78 | if (i == -1) { 79 | if (errno == EINTR) { 80 | i = 0; 81 | } else { 82 | printf("Error during sendall: %d. errno=%d\n", (int)i, errno); 83 | return i; 84 | } 85 | } 86 | totalsent += i; 87 | sizeleft -= i; 88 | } 89 | 90 | return totalsent; 91 | } 92 | 93 | int DispatchCommand(int currentsocket, unsigned char command) { 94 | int r; 95 | switch (command) { 96 | case CMD_GETVERSION: { 97 | CeVersion *v; 98 | int versionsize = strlen(versionstring); 99 | v = (CeVersion *)malloc(sizeof(CeVersion) + versionsize); 100 | v->stringsize = versionsize; 101 | v->version = 6; 102 | 103 | memcpy((char *)v + sizeof(CeVersion), versionstring, versionsize); 104 | 105 | // version request 106 | sendall(currentsocket, v, sizeof(CeVersion) + versionsize, 0); 107 | 108 | free(v); 109 | 110 | break; 111 | } 112 | 113 | case CMD_GETARCHITECTURE: { 114 | #ifdef __i386__ 115 | unsigned char arch = 0; 116 | #endif 117 | #ifdef __x86_64__ 118 | unsigned char arch = 1; 119 | #endif 120 | #ifdef __arm__ 121 | unsigned char arch = 2; 122 | #endif 123 | #ifdef __aarch64__ 124 | unsigned char arch = 3; 125 | #endif 126 | 127 | HANDLE h; 128 | // ce 7.4.1+ : Added the processhandle 129 | 130 | if (recvall(currentsocket, &h, sizeof(h), MSG_WAITALL) > 0) { 131 | // intel i386=0 132 | // intel x86_64=1 133 | // arm 32 = 2 134 | // arm 64 = 3 135 | // TODO 136 | } 137 | 138 | sendall(currentsocket, &arch, sizeof(arch), 0); 139 | break; 140 | } 141 | 142 | case CMD_CLOSECONNECTION: { 143 | printf("Connection %d closed properly\n", currentsocket); 144 | fflush(stdout); 145 | close(currentsocket); 146 | 147 | return 0; 148 | } 149 | 150 | case CMD_TERMINATESERVER: { 151 | printf("Command to terminate the server received\n"); 152 | fflush(stdout); 153 | close(currentsocket); 154 | exit(0); 155 | } 156 | 157 | case CMD_STARTDEBUG: { 158 | printf("[NOT SUPPORT!] CMD_STARTDEBUG\n"); 159 | break; 160 | } 161 | case CMD_WAITFORDEBUGEVENT: { 162 | printf("[NOT SUPPORT!] CMD_WAITFORDEBUGEVENT\n"); 163 | break; 164 | } 165 | case CMD_CONTINUEFROMDEBUGEVENT: { 166 | printf("[NOT SUPPORT!] CMD_CONTINUEFROMDEBUGEVENT\n"); 167 | break; 168 | } 169 | case CMD_SETBREAKPOINT: { 170 | printf("[NOT SUPPORT!] CMD_SETBREAKPOINT\n"); 171 | break; 172 | } 173 | case CMD_REMOVEBREAKPOINT: { 174 | printf("[NOT SUPPORT!] CMD_REMOVEBREAKPOINT\n"); 175 | break; 176 | } 177 | 178 | case CMD_GETTHREADCONTEXT: { 179 | printf("[NOT SUPPORT!] CMD_GETTHREADCONTEXT\n"); 180 | break; 181 | } 182 | case CMD_SETTHREADCONTEXT: { 183 | printf("[NOT SUPPORT!] CMD_SETTHREADCONTEXT\n"); 184 | break; 185 | } 186 | case CMD_SUSPENDTHREAD: { 187 | printf("[NOT SUPPORT!] CMD_SUSPENDTHREAD\n"); 188 | break; 189 | } 190 | case CMD_RESUMETHREAD: { 191 | printf("[NOT SUPPORT!] CMD_RESUMETHREAD\n"); 192 | break; 193 | } 194 | case CMD_CLOSEHANDLE: { 195 | HANDLE h; 196 | if (recvall(currentsocket, &h, sizeof(h), MSG_WAITALL) > 0) { 197 | printf("CMD_CLOSEHANDLE(%d)\n", h); 198 | CApi::CloseHandle(h); 199 | int r = 1; 200 | sendall(currentsocket, &r, sizeof(r), 0); // stupid naggle 201 | } else { 202 | printf("Error during read for CMD_CLOSEHANDLE\n"); 203 | close(currentsocket); 204 | fflush(stdout); 205 | return 0; 206 | } 207 | break; 208 | } 209 | 210 | case CMD_CREATETOOLHELP32SNAPSHOT: { 211 | CeCreateToolhelp32Snapshot params; 212 | HANDLE result; 213 | 214 | printf("CMD_CREATETOOLHELP32SNAPSHOT\n"); 215 | 216 | if (recvall(currentsocket, ¶ms, sizeof(CeCreateToolhelp32Snapshot), MSG_WAITALL) > 0) { 217 | // printf("Calling CreateToolhelp32Snapshot\n"); 218 | 219 | result = CApi::CreateToolhelp32Snapshot(params.dwFlags, params.th32ProcessID); 220 | 221 | printf("result of CreateToolhelp32Snapshot=%d\n", result); 222 | 223 | fflush(stdout); 224 | sendall(currentsocket, &result, sizeof(HANDLE), 0); 225 | 226 | } else { 227 | printf("Error during read for CMD_CREATETOOLHELP32SNAPSHOT\n"); 228 | fflush(stdout); 229 | close(currentsocket); 230 | return 0; 231 | } 232 | 233 | break; 234 | } 235 | 236 | case CMD_PROCESS32FIRST: // obsolete 237 | case CMD_PROCESS32NEXT: { 238 | HANDLE toolhelpsnapshot; 239 | if (recvall(currentsocket, &toolhelpsnapshot, sizeof(toolhelpsnapshot), MSG_WAITALL) > 0) { 240 | // printf("CMD_PROCESS32FIRST || CMD_PROCESS32NEXT %d\n", toolhelpsnapshot); 241 | 242 | ProcessListEntry pe; 243 | BOOL result = FALSE; 244 | CeProcessEntry *r; 245 | int size; 246 | 247 | if (command == CMD_PROCESS32FIRST) { 248 | result = CApi::Process32First(toolhelpsnapshot, pe); 249 | // printf("Process32First result=%d\n", result); 250 | } else { 251 | result = CApi::Process32Next(toolhelpsnapshot, pe); 252 | // printf("Process32Next result=%d\n", result); 253 | } 254 | 255 | if (result) { 256 | size = sizeof(CeProcessEntry) + pe.ProcessName.length(); 257 | r = (CeProcessEntry *)malloc(size); 258 | r->processnamesize = pe.ProcessName.length(); 259 | r->pid = pe.PID; 260 | memcpy((char *)r + sizeof(CeProcessEntry), pe.ProcessName.c_str(), r->processnamesize); 261 | } else { 262 | size = sizeof(CeProcessEntry); 263 | r = (CeProcessEntry *)malloc(size); 264 | r->processnamesize = 0; 265 | r->pid = 0; 266 | } 267 | r->result = result; 268 | sendall(currentsocket, r, size, 0); 269 | free(r); 270 | } 271 | break; 272 | } 273 | 274 | case CMD_MODULE32FIRST: // slightly obsolete now 275 | case CMD_MODULE32NEXT: { 276 | HANDLE toolhelpsnapshot; 277 | if (recvall(currentsocket, &toolhelpsnapshot, sizeof(toolhelpsnapshot), MSG_WAITALL) > 0) { 278 | BOOL result; 279 | ModuleListEntry me; 280 | CeModuleEntry *r; 281 | int size; 282 | 283 | if (command == CMD_MODULE32FIRST) { 284 | result = CApi::Module32First(toolhelpsnapshot, me); 285 | } else { 286 | result = CApi::Module32Next(toolhelpsnapshot, me); 287 | } 288 | 289 | if (result) { 290 | size = sizeof(CeModuleEntry) + me.moduleName.length(); 291 | r = (CeModuleEntry *)malloc(size); 292 | r->modulebase = me.baseAddress; 293 | r->modulesize = me.moduleSize; 294 | r->modulenamesize = me.moduleName.length(); 295 | r->modulefileoffset = 0; 296 | r->modulepart = 0; 297 | // printf("%s\n", me.moduleName.c_str()); 298 | 299 | // Sending %s size %x\n, me.moduleName, r->modulesize 300 | memcpy((char *)r + sizeof(CeModuleEntry), me.moduleName.c_str(), r->modulenamesize); 301 | } else { 302 | size = sizeof(CeModuleEntry); 303 | r = (CeModuleEntry *)malloc(size); 304 | r->modulebase = 0; 305 | r->modulesize = 0; 306 | r->modulenamesize = 0; 307 | r->modulefileoffset = 0; 308 | r->modulepart = 0; 309 | } 310 | 311 | r->result = result; 312 | 313 | sendall(currentsocket, r, size, 0); 314 | 315 | free(r); 316 | } 317 | break; 318 | } 319 | 320 | case CMD_OPENPROCESS: { 321 | int pid = 0; 322 | 323 | r = recvall(currentsocket, &pid, sizeof(int), MSG_WAITALL); 324 | if (r > 0) { 325 | int processhandle; 326 | 327 | printf("OpenProcess(%d)\n", pid); 328 | processhandle = CApi::OpenProcess(pid); 329 | 330 | printf("processhandle=%d\n", processhandle); 331 | sendall(currentsocket, &processhandle, sizeof(int), 0); 332 | } else { 333 | printf("Error\n"); 334 | fflush(stdout); 335 | close(currentsocket); 336 | return 0; 337 | } 338 | break; 339 | } 340 | 341 | case CMD_READPROCESSMEMORY: { 342 | CeReadProcessMemoryInput c; 343 | 344 | r = recvall(currentsocket, &c, sizeof(c), MSG_WAITALL); 345 | if (r > 0) { 346 | CeReadProcessMemoryOutput *o = NULL; 347 | o = (CeReadProcessMemoryOutput *)malloc(sizeof(CeReadProcessMemoryOutput) + c.size); 348 | memset(o, 0, sizeof(CeReadProcessMemoryOutput) + c.size); 349 | 350 | o->read = CApi::ReadProcessMemory(c.handle, (void *)(uintptr_t)c.address, &o[1], c.size); 351 | 352 | if (c.compress) { 353 | // printf("ReadProcessMemory compress %d %p %d\n", c.handle, c.address, c.size); 354 | 355 | // compress the output 356 | #define COMPRESS_BLOCKSIZE (64 * 1024) 357 | int i; 358 | unsigned char *uncompressed = (unsigned char *)&o[1]; 359 | uint32_t uncompressedSize = o->read; 360 | uint32_t compressedSize = 0; 361 | int maxBlocks = 1 + (c.size / COMPRESS_BLOCKSIZE); 362 | 363 | unsigned char **compressedBlocks = 364 | (unsigned char **)malloc(maxBlocks * sizeof(unsigned char *)); // send in blocks of 64kb and reallocate the pointerblock if there's not enough space 365 | int currentBlock = 0; 366 | 367 | z_stream strm; 368 | strm.zalloc = Z_NULL; 369 | strm.zfree = Z_NULL; 370 | strm.opaque = Z_NULL; 371 | deflateInit(&strm, c.compress); 372 | 373 | compressedBlocks[currentBlock] = (unsigned char *)malloc(COMPRESS_BLOCKSIZE); 374 | strm.avail_out = COMPRESS_BLOCKSIZE; 375 | strm.next_out = compressedBlocks[currentBlock]; 376 | 377 | strm.next_in = uncompressed; 378 | strm.avail_in = uncompressedSize; 379 | 380 | while (strm.avail_in) { 381 | r = deflate(&strm, Z_NO_FLUSH); 382 | if (r != Z_OK) { 383 | if (r == Z_STREAM_END) 384 | break; 385 | else { 386 | printf("Error while compressing\n"); 387 | break; 388 | } 389 | } 390 | 391 | if (strm.avail_out == 0) { 392 | // new output block 393 | currentBlock++; 394 | if (currentBlock >= maxBlocks) { 395 | // list was too short, reallocate 396 | printf("Need to realloc the pointerlist (p1)\n"); 397 | 398 | maxBlocks *= 2; 399 | compressedBlocks = (unsigned char **)realloc(compressedBlocks, maxBlocks * sizeof(unsigned char *)); 400 | } 401 | compressedBlocks[currentBlock] = (unsigned char *)malloc(COMPRESS_BLOCKSIZE); 402 | strm.avail_out = COMPRESS_BLOCKSIZE; 403 | strm.next_out = compressedBlocks[currentBlock]; 404 | } 405 | } 406 | // finishing compressiong 407 | while (1) { 408 | 409 | r = deflate(&strm, Z_FINISH); 410 | 411 | if (r == Z_STREAM_END) 412 | break; // done 413 | 414 | if (r != Z_OK) { 415 | printf("Failure while finishing compression:%d\n", r); 416 | break; 417 | } 418 | 419 | if (strm.avail_out == 0) { 420 | // new output block 421 | currentBlock++; 422 | if (currentBlock >= maxBlocks) { 423 | // list was too short, reallocate 424 | printf("Need to realloc the pointerlist (p2)\n"); 425 | maxBlocks *= 2; 426 | compressedBlocks = (unsigned char **)realloc(compressedBlocks, maxBlocks * sizeof(unsigned char *)); 427 | } 428 | compressedBlocks[currentBlock] = (unsigned char *)malloc(COMPRESS_BLOCKSIZE); 429 | strm.avail_out = COMPRESS_BLOCKSIZE; 430 | strm.next_out = compressedBlocks[currentBlock]; 431 | } 432 | } 433 | deflateEnd(&strm); 434 | 435 | compressedSize = strm.total_out; 436 | // Sending compressed data 437 | sendall(currentsocket, &uncompressedSize, sizeof(uncompressedSize), MSG_MORE); // followed by the compressed size 438 | sendall(currentsocket, &compressedSize, sizeof(compressedSize), MSG_MORE); // the compressed data follows 439 | for (i = 0; i <= currentBlock; i++) { 440 | if (i != currentBlock) 441 | sendall(currentsocket, compressedBlocks[i], COMPRESS_BLOCKSIZE, MSG_MORE); 442 | else 443 | sendall(currentsocket, compressedBlocks[i], COMPRESS_BLOCKSIZE - strm.avail_out, 0); // last one, flush 444 | 445 | free(compressedBlocks[i]); 446 | } 447 | free(compressedBlocks); 448 | } else { 449 | // printf("ReadProcessMemory Uncompress %d %p %d\n", c.handle, c.address, c.size); 450 | sendall(currentsocket, o, sizeof(CeReadProcessMemoryOutput) + o->read, 0); 451 | } 452 | 453 | if (o) { 454 | free(o); 455 | } 456 | } 457 | break; 458 | } 459 | 460 | case CMD_WRITEPROCESSMEMORY: { 461 | CeWriteProcessMemoryInput c; 462 | 463 | printf("CMD_WRITEPROCESSMEMORY:\n"); 464 | 465 | r = recvall(currentsocket, &c, sizeof(c), MSG_WAITALL); 466 | if (r > 0) { 467 | CeWriteProcessMemoryOutput o; 468 | unsigned char *buf; 469 | 470 | printf("recv returned %d bytes\n", r); 471 | printf("c.size=%d\n", c.size); 472 | 473 | if (c.size) { 474 | buf = (unsigned char *)malloc(c.size); 475 | 476 | r = recvall(currentsocket, buf, c.size, MSG_WAITALL); 477 | if (r > 0) { 478 | printf("received %d bytes for the buffer. Wanted %d\n", r, c.size); 479 | o.written = CApi::WriteProcessMemory(c.handle, (void *)(uintptr_t)c.address, buf, c.size); 480 | 481 | r = sendall(currentsocket, &o, sizeof(CeWriteProcessMemoryOutput), 0); 482 | printf("wpm: returned %d bytes to caller\n", r); 483 | 484 | } else { 485 | printf("wpm recv error while reading the data\n"); 486 | } 487 | free(buf); 488 | } else { 489 | printf("wpm with a size of 0 bytes"); 490 | o.written = 0; 491 | r = sendall(currentsocket, &o, sizeof(CeWriteProcessMemoryOutput), 0); 492 | printf("wpm: returned %d bytes to caller\n", r); 493 | } 494 | } else { 495 | printf("RPM: recv failed\n"); 496 | } 497 | break; 498 | } 499 | case CMD_VIRTUALQUERYEXFULL: { 500 | // printf("CMD_VIRTUALQUERYEXFULL\n"); 501 | 502 | CeVirtualQueryExFullInput c; 503 | CeVirtualQueryExFullOutput o; 504 | 505 | r = recvall(currentsocket, &c, sizeof(c), MSG_WAITALL); 506 | if (r > 0) { 507 | std::vector vRinfo; 508 | if (CApi::VirtualQueryExFull(c.handle, c.flags, vRinfo)) { 509 | // printf("VirtualQueryExFull ok %d\n", vRinfo.size()); 510 | uint32_t count = vRinfo.size(); 511 | sendall(currentsocket, &count, sizeof(count), 0); 512 | 513 | for (RegionInfo r : vRinfo) { 514 | sendall(currentsocket, &r, sizeof(r), 0); 515 | } 516 | // printf("VirtualQueryExFull all %d\n", vRinfo.size()); 517 | } else { 518 | // printf("VirtualQueryExFull no %d\n", vRinfo.size()); 519 | uint32_t count = 0; 520 | sendall(currentsocket, &count, sizeof(count), 0); 521 | } 522 | } 523 | break; 524 | } 525 | case CMD_GETREGIONINFO: 526 | case CMD_VIRTUALQUERYEX: { 527 | 528 | CeVirtualQueryExInput c; 529 | r = recvall(currentsocket, &c, sizeof(c), MSG_WAITALL); 530 | if (r > 0) { 531 | RegionInfo rinfo; 532 | CeVirtualQueryExOutput o; 533 | if (sizeof(uintptr_t) == 4) { 534 | if (c.baseaddress > 0xFFFFFFFF) { 535 | o.result = 0; 536 | sendall(currentsocket, &o, sizeof(o), 0); 537 | break; 538 | } 539 | } 540 | 541 | std::string mapsline; 542 | 543 | if (command == CMD_VIRTUALQUERYEX) { 544 | // printf("CMD_VIRTUALQUERYEX\n"); 545 | o.result = CApi::VirtualQueryEx(c.handle, c.baseaddress, rinfo, mapsline); 546 | } else if (command == CMD_GETREGIONINFO) { 547 | // printf("CMD_GETREGIONINFO\n"); 548 | o.result = CApi::VirtualQueryEx(c.handle, c.baseaddress, rinfo, mapsline); 549 | } 550 | 551 | o.protection = rinfo.protection; 552 | o.baseaddress = rinfo.baseaddress; 553 | o.type = rinfo.type; 554 | o.size = rinfo.size; 555 | 556 | if (command == CMD_VIRTUALQUERYEX) { 557 | sendall(currentsocket, &o, sizeof(o), 0); 558 | } else if (command == CMD_GETREGIONINFO) { 559 | sendall(currentsocket, &o, sizeof(o), MSG_MORE); 560 | { 561 | uint8_t size = mapsline.length(); 562 | sendall(currentsocket, &size, sizeof(size), MSG_MORE); 563 | 564 | if (size) { 565 | sendall(currentsocket, (void *)mapsline.c_str(), size, 0); 566 | } 567 | } 568 | } 569 | } 570 | break; 571 | } 572 | 573 | case CMD_GETSYMBOLLISTFROMFILE: { 574 | // get the list and send it to the client 575 | // zip it first 576 | uint32_t symbolpathsize; 577 | 578 | 579 | if (recvall(currentsocket, &symbolpathsize, sizeof(symbolpathsize), MSG_WAITALL) > 0) { 580 | char *symbolpath = (char *)malloc(symbolpathsize + 1); 581 | symbolpath[symbolpathsize] = '\0'; 582 | 583 | if (recvall(currentsocket, symbolpath, symbolpathsize, MSG_WAITALL) > 0) { 584 | unsigned char *output = NULL; 585 | 586 | // printf("symbolpath=%s\n", symbolpath); 587 | 588 | if (memcmp("/dev/", symbolpath, 5) != 0) // don't even bother if it's a /dev/ file 589 | { 590 | // 因为这里需要open本地的.so文件,有可能会被反调试手段侦测到,而且作用不太大,所以暂时屏蔽掉。 591 | // 解决方法一(待实现):在被调试进程启动前,读取本地.so文件 592 | // GetSymbolListFromFile(symbolpath, &output); 593 | } 594 | if (output) { 595 | // printf("output is not NULL (%p)\n", output); 596 | 597 | fflush(stdout); 598 | 599 | // printf("Sending %d bytes\n", *(uint32_t *)&output[4]); 600 | sendall(currentsocket, output, *(uint32_t *)&output[4], 0); // the output buffer contains the size itself 601 | free(output); 602 | } else { 603 | 604 | // printf("Sending 8 bytes (fail)\n"); 605 | uint64_t fail = 0; 606 | sendall(currentsocket, &fail, sizeof(fail), 0); // just write 0 607 | } 608 | } else { 609 | printf("Failure getting symbol path\n"); 610 | close(currentsocket); 611 | } 612 | 613 | free(symbolpath); 614 | } 615 | break; 616 | } 617 | 618 | case CMD_LOADEXTENSION: { 619 | printf("[NOT SUPPORT!] CMD_LOADEXTENSION\n"); 620 | break; 621 | } 622 | 623 | case CMD_ALLOC: { 624 | printf("[NOT SUPPORT!] CMD_ALLOC\n"); 625 | break; 626 | } 627 | case CMD_FREE: { 628 | printf("[NOT SUPPORT!] CMD_FREE\n"); 629 | break; 630 | } 631 | case CMD_CREATETHREAD: { 632 | printf("[NOT SUPPORT!] CMD_CREATETHREAD\n"); 633 | break; 634 | } 635 | case CMD_LOADMODULE: { 636 | printf("[NOT SUPPORT!] CMD_LOADMODULE\n"); 637 | break; 638 | } 639 | case CMD_SPEEDHACK_SETSPEED: { 640 | printf("[NOT SUPPORT!] CMD_SPEEDHACK_SETSPEED\n"); 641 | break; 642 | } 643 | case CMD_AOBSCAN: { 644 | CeAobScanInput c; 645 | printf("CESERVER: CMD_AOBSCAN\n"); 646 | if (recvall(currentsocket, &c, sizeof(c), 0) > 0) { 647 | 648 | int n = c.scansize; 649 | char *data = (char *)malloc(n * 2); 650 | uint64_t *match_addr = (uint64_t *)malloc(sizeof(uint64_t) * MAX_HIT_COUNT); 651 | 652 | if (recvall(currentsocket, data, n * 2, 0) > 0) { 653 | char *pattern = (char *)malloc(n); 654 | char *mask = (char *)malloc(n); 655 | 656 | memcpy(pattern, data, n); 657 | memcpy(mask, &data[n], n); 658 | int ret = 0; // AOBScan(c.hProcess, pattern, mask, c.start, c.end, c.inc, c.protection, match_addr); 659 | printf("HIT_COUNT:%d\n", ret); 660 | free(pattern); 661 | free(mask); 662 | sendall(currentsocket, &ret, 4, 0); 663 | sendall(currentsocket, match_addr, sizeof(uint64_t) * ret, 0); 664 | } 665 | free(data); 666 | free(match_addr); 667 | } 668 | 669 | break; 670 | } 671 | case CMD_CREATETOOLHELP32SNAPSHOTEX: { 672 | CeCreateToolhelp32Snapshot params; 673 | // debug_log("CMD_CREATETOOLHELP32SNAPSHOTEX\n"); 674 | 675 | if (recvall(currentsocket, ¶ms, sizeof(CeCreateToolhelp32Snapshot), MSG_WAITALL) > 0) { 676 | HANDLE r = CApi::CreateToolhelp32Snapshot(params.dwFlags, params.th32ProcessID); 677 | 678 | if ((params.dwFlags & TH32CS_SNAPTHREAD) == TH32CS_SNAPTHREAD) { 679 | // send the list of threadid's 680 | 681 | if (r) { 682 | ThreadList *tl = (ThreadList *)CPortHelper::GetPointerFromHandle(r); 683 | sendall(currentsocket, &tl->threadCount, sizeof(int), MSG_MORE); 684 | sendall(currentsocket, &tl->threadList[0], tl->threadCount * sizeof(int), 0); 685 | 686 | CApi::CloseHandle(r); 687 | } else { 688 | int n = 0; 689 | sendall(currentsocket, &n, sizeof(int), 0); 690 | } 691 | } else if ((params.dwFlags & TH32CS_SNAPMODULE) == TH32CS_SNAPMODULE) { 692 | ModuleListEntry me; 693 | 694 | char *outputstream; 695 | int pos = 0; 696 | 697 | // debug_log("CMD_CREATETOOLHELP32SNAPSHOTEX with TH32CS_SNAPMODULE\n"); 698 | 699 | outputstream = (char *)calloc(65536, 1); 700 | 701 | if (r && (CApi::Module32First(r, me))) 702 | do { 703 | int namelen = me.moduleName.length(); 704 | CeModuleEntry *m; 705 | 706 | if ((pos + sizeof(CeModuleEntry) + namelen) > 65536) { 707 | // flush the stream 708 | // debug_log("CMD_CREATETOOLHELP32SNAPSHOTEX: ModuleList flush in loop\n"); 709 | sendall(currentsocket, outputstream, pos, 0); 710 | pos = 0; 711 | } 712 | 713 | m = (CeModuleEntry *)&outputstream[pos]; 714 | m->modulebase = me.baseAddress; 715 | m->modulesize = me.moduleSize; 716 | m->modulenamesize = namelen; 717 | m->modulefileoffset = 0; 718 | m->modulepart = 0; 719 | m->result = 1; 720 | 721 | // Sending %s size %x\n, me.moduleName, r->modulesize 722 | memcpy((char *)m + sizeof(CeModuleEntry), me.moduleName.data(), namelen); 723 | 724 | pos += sizeof(CeModuleEntry) + namelen; 725 | 726 | } while (CApi::Module32Next(r, me)); 727 | 728 | if (pos) // flush the stream 729 | { 730 | // debug_log("CMD_CREATETOOLHELP32SNAPSHOTEX: ModuleList flush after loop\n"); 731 | sendall(currentsocket, outputstream, pos, 0); 732 | } 733 | 734 | // send the end of list module 735 | // debug_log("CMD_CREATETOOLHELP32SNAPSHOTEX: ModuleList end of list\n"); 736 | 737 | CeModuleEntry eol; 738 | eol.result = 0; 739 | eol.modulenamesize = 0; 740 | sendall(currentsocket, &eol, sizeof(eol), 0); 741 | 742 | free(outputstream); 743 | 744 | if (r) 745 | CApi::CloseHandle(r); 746 | 747 | } else { 748 | sendall(currentsocket, &r, sizeof(HANDLE), 0); // the others are not yet implemented 749 | } 750 | } else { 751 | printf("Error during read for CMD_CREATETOOLHELP32SNAPSHOTEX\n"); 752 | fflush(stdout); 753 | close(currentsocket); 754 | return 0; 755 | } 756 | break; 757 | } 758 | case CMD_GETOPTIONS: { 759 | uint16_t count = 0; 760 | sendall(currentsocket, &count, sizeof(count), 0); 761 | break; 762 | } 763 | case CMD_GETABI: { 764 | #ifdef WINDOWS 765 | unsigned char abi = 0; 766 | #else 767 | unsigned char abi = 1; 768 | #endif 769 | sendall(currentsocket, &abi, sizeof(abi), 0); 770 | break; 771 | } 772 | case CMD_ISANDROID: { 773 | unsigned char r; 774 | #ifdef __ANDROID__ 775 | r = 1; 776 | #else 777 | r = 0; 778 | #endif 779 | sendall(currentsocket, &r, sizeof(r), 0); 780 | 781 | break; 782 | } 783 | default: 784 | printf("Unknow command:%d\n", command); 785 | fflush(stdout); 786 | break; 787 | } 788 | return 0; 789 | } 790 | 791 | void newConnectionThread(int s) { 792 | unsigned char command; 793 | 794 | int currentsocket = s; 795 | 796 | // printf("new connection. Using socket %d\n", s); 797 | while (1) { 798 | int r = recvall(currentsocket, &command, 1, MSG_WAITALL); 799 | 800 | if (r > 0) { 801 | DispatchCommand(currentsocket, command); 802 | } else if (r == -1) { 803 | printf("read error on socket %d (%d)\n", s, errno); 804 | fflush(stdout); 805 | close(currentsocket); 806 | return; 807 | } else { 808 | if (r == 0) { 809 | printf("Peer has disconnected\n"); 810 | fflush(stdout); 811 | close(currentsocket); 812 | return; 813 | } 814 | } 815 | } 816 | close(s); 817 | return; 818 | } 819 | 820 | void IdentifierThread() { 821 | int i; 822 | int s; 823 | int v = 1; 824 | #pragma pack(1) 825 | struct { 826 | uint32_t checksum; 827 | uint16_t port; 828 | } packet; 829 | #pragma pack() 830 | 831 | socklen_t clisize; 832 | struct sockaddr_in addr, addr_client; 833 | 834 | printf("IdentifierThread active\n"); 835 | 836 | fflush(stdout); 837 | 838 | s = socket(PF_INET, SOCK_DGRAM, 0); 839 | i = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &v, sizeof(v)); 840 | 841 | memset(&addr, 0, sizeof(addr)); 842 | 843 | addr.sin_family = PF_INET; 844 | addr.sin_addr.s_addr = INADDR_ANY; 845 | addr.sin_port = htons(3296); 846 | i = bind(s, (struct sockaddr *)&addr, sizeof(addr)); 847 | 848 | if (i >= 0) { 849 | while (1) { 850 | memset(&addr_client, 0, sizeof(addr_client)); 851 | addr_client.sin_family = PF_INET; 852 | addr_client.sin_addr.s_addr = INADDR_ANY; 853 | addr_client.sin_port = htons(3296); 854 | 855 | clisize = sizeof(addr_client); 856 | 857 | i = recvfrom(s, &packet, sizeof(packet), 0, (struct sockaddr *)&addr_client, &clisize); 858 | 859 | // i=recv(s, &v, sizeof(v), 0); 860 | if (i >= 0) { 861 | 862 | printf("Identifier thread received a message :%d\n", v); 863 | printf("sizeof(packet)=%d\n", (int)sizeof(packet)); 864 | 865 | printf("packet.checksum=%x\n", packet.checksum); 866 | packet.checksum *= 0xce; 867 | packet.port = PORT; 868 | printf("packet.checksum=%x\n", packet.checksum); 869 | 870 | // packet.checksum=00AE98E7 - y=8C7F09E2 871 | 872 | fflush(stdout); 873 | 874 | i = sendto(s, &packet, sizeof(packet), 0, (struct sockaddr *)&addr_client, clisize); 875 | printf("sendto returned %d\n", i); 876 | } else { 877 | printf("recvfrom failed\n"); 878 | } 879 | 880 | fflush(stdout); 881 | } 882 | } else { 883 | printf("IdentifierThread bind port failed\n"); 884 | } 885 | printf("IdentifierThread exit\n"); 886 | return; 887 | } 888 | 889 | int main(int argc, char *argv[]) { 890 | // 初始化读写驱动 891 | if (!CApi::InitReadWriteDriver(argc > 1 ? argv[1] : NULL, FALSE)) { 892 | printf("Init read write driver failed.\n"); 893 | return 0; 894 | } 895 | 896 | socklen_t clisize; 897 | struct sockaddr_in addr, addr_client; 898 | 899 | printf("listening on port %d\n", PORT); 900 | 901 | printf("CEServer. Waiting for client connection\n"); 902 | 903 | // if (broadcast) 904 | 905 | std::thread tdId(IdentifierThread); 906 | tdId.detach(); 907 | 908 | int s = socket(AF_INET, SOCK_STREAM, 0); 909 | printf("socket=%d\n", s); 910 | 911 | memset(&addr, 0, sizeof(addr)); 912 | addr.sin_family = AF_INET; 913 | addr.sin_port = htons(PORT); 914 | addr.sin_addr.s_addr = INADDR_ANY; 915 | 916 | int optval = 1; 917 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); // 让端口释放后立即就可以被再次使用 918 | 919 | int b = bind(s, (struct sockaddr *)&addr, sizeof(addr)); 920 | printf("bind=%d\n", b); 921 | 922 | if (b != -1) { 923 | int l = listen(s, 32); 924 | 925 | printf("listen=%d\n", l); 926 | 927 | clisize = sizeof(addr_client); 928 | memset(&addr_client, 0, sizeof(addr_client)); 929 | 930 | fflush(stdout); 931 | 932 | while (1) { 933 | 934 | int a = accept(s, (struct sockaddr *)&addr_client, &clisize); 935 | 936 | printf("accept=%d\n", a); 937 | 938 | fflush(stdout); 939 | int opt = 1; 940 | setsockopt(a, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); 941 | 942 | if (a != -1) { 943 | std::thread tdConnect(newConnectionThread, a); 944 | tdConnect.detach(); 945 | } 946 | } 947 | } 948 | 949 | printf("Terminate server\n"); 950 | 951 | close(s); 952 | 953 | return 0; 954 | } --------------------------------------------------------------------------------