【Android 逆向】代码调试器开发 ( ptrace 函数 | 向进程内存写出数据 )
文章目錄
- 一、向進(jìn)程內(nèi)存寫(xiě)出數(shù)據(jù)
- 二、寫(xiě)出流程
- 三、完整代碼
一、向進(jìn)程內(nèi)存寫(xiě)出數(shù)據(jù)
向內(nèi)存寫(xiě)出數(shù)據(jù) : 每次最多能寫(xiě)出 4 字節(jié) ;
ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);- 參數(shù)一 : 寫(xiě)出數(shù)據(jù)標(biāo)志 PTRACE_POKETEXT ;
- 參數(shù)二 : 進(jìn)程號(hào) PID ;
- 參數(shù)三 : 寫(xiě)出去數(shù)據(jù)的地址 ;
- 參數(shù)四 : 寫(xiě)出的數(shù)據(jù)內(nèi)容 , 4 字節(jié) ;
二、寫(xiě)出流程
向進(jìn)程內(nèi)存寫(xiě)出數(shù)據(jù)時(shí) , 每次最多只能寫(xiě)出 4 字節(jié)數(shù)據(jù) , 先根據(jù)讀取的大小 , 計(jì)算出讀取次數(shù) ,
// 每次讀取 4 字節(jié) , 讀取次數(shù)為 nSize / 4j = nSize / 4;然后再計(jì)算出最后不足 4 字節(jié)的部分 ,
// 讀取最后不滿 4 個(gè)字節(jié)的數(shù)據(jù) remain = nSize % 4;讀取數(shù)據(jù)時(shí) , 先循環(huán) j 次 , 寫(xiě)出 j x 4 字節(jié)數(shù)據(jù) ,
for (i = 0; i < j; i++) {// 準(zhǔn)備寫(xiě)出數(shù)據(jù) , 從 laddr 拷貝到 d.charsmemcpy(d.chars, laddr, 4);// 32 位的設(shè)備上 , 最長(zhǎng)只能讀取 4 字節(jié) ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);pDestAddr += 4;laddr += 4;}最后再讀取一次末尾不足 4 字節(jié)的數(shù)據(jù) ;
讀取的時(shí)候 , 如果不足 4 字節(jié) , 我們可以將數(shù)據(jù)直接讀取出來(lái) , 不影響程序運(yùn)行 ; 寫(xiě)出的時(shí)候 , 如果寫(xiě)出數(shù)據(jù)不足 4 字節(jié) , 是 3 字節(jié) , 那么必須保證最后一位寫(xiě)出時(shí) , 不會(huì)出錯(cuò) , 原來(lái)進(jìn)程中 第 4 位是什么數(shù)據(jù) , 寫(xiě)出去時(shí)也必須是同樣的數(shù)據(jù) , 否則進(jìn)程運(yùn)行出錯(cuò) ;
先 讀取 當(dāng)前進(jìn)程內(nèi)存的數(shù)據(jù) ,
// 一次性必須寫(xiě)入 4 字節(jié) , 如果不足 4 字節(jié) , 先把數(shù)據(jù)讀取出來(lái) , 即讀取 4 字節(jié)出來(lái) d.val = ptrace(PTRACE_PEEKTEXT, m_nPid, (void*)pDestAddr, 0);然后 , 設(shè)置數(shù)據(jù) ; 假如數(shù)據(jù)有 3 字節(jié) , 那么就將上述讀取的 4 字節(jié)的前 3 個(gè)字節(jié)設(shè)置成我們要修改的數(shù)據(jù) , 這就保證了第 4 個(gè)字節(jié)不會(huì)出錯(cuò) ;
// 假如數(shù)據(jù)有 3 字節(jié) , 那么就將上述讀取的 4 字節(jié)的前 3 個(gè)字節(jié)設(shè)置成我們要修改的數(shù)據(jù) // 這就保證了第 4 個(gè)字節(jié)不會(huì)出錯(cuò) for (i = 0; i < remain; i++) {d.chars[i] = *laddr++;}最后 , 將最終的 4 字節(jié)數(shù)據(jù)寫(xiě)入進(jìn)程內(nèi)存 ;
// 最后將最終的 4 字節(jié)數(shù)據(jù)寫(xiě)入進(jìn)程內(nèi)存ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);//整體寫(xiě)入部分代碼示例 :
// 寫(xiě)出末尾不足 4 字節(jié)的數(shù)據(jù)部分 // 讀取的時(shí)候 , 如果不足 4 字節(jié) , 我們可以將數(shù)據(jù)直接讀取出來(lái) , 不影響程序運(yùn)行 // 寫(xiě)出的時(shí)候 , 如果寫(xiě)出數(shù)據(jù)不足 4 字節(jié) , 是 3 字節(jié) , 那么必須保證最后一位寫(xiě)出時(shí) , 不會(huì)出錯(cuò) , // 原來(lái)進(jìn)程中 第 4 位是什么數(shù)據(jù) , 寫(xiě)出去時(shí)也必須是同樣的數(shù)據(jù) , 否則進(jìn)程運(yùn)行出錯(cuò) if (remain > 0) {// 一次性必須寫(xiě)入 4 字節(jié) , 如果不足 4 字節(jié) , 先把數(shù)據(jù)讀取出來(lái) , 即讀取 4 字節(jié)出來(lái) d.val = ptrace(PTRACE_PEEKTEXT, m_nPid, (void*)pDestAddr, 0);// 假如數(shù)據(jù)有 3 字節(jié) , 那么就將上述讀取的 4 字節(jié)的前 3 個(gè)字節(jié)設(shè)置成我們要修改的數(shù)據(jù) // 這就保證了第 4 個(gè)字節(jié)不會(huì)出錯(cuò) for (i = 0; i < remain; i++) {d.chars[i] = *laddr++;}// 最后將最終的 4 字節(jié)數(shù)據(jù)ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);//整體寫(xiě)入}三、完整代碼
向進(jìn)程內(nèi)存寫(xiě)出數(shù)據(jù)完整代碼 :
// pDestAddr 寫(xiě)出地址 , const char* pData 寫(xiě)出的數(shù)據(jù) , size_t nSize 寫(xiě)出數(shù)據(jù)大小 int CPtrace::write(char* pDestAddr, const char* pData, size_t nSize) {uint32_t i, j, remain;// 寫(xiě)出數(shù)據(jù)的地址 , 該地址需要不斷累加計(jì)算 , 記錄寫(xiě)出的數(shù)據(jù)地址 const char *laddr;// 聯(lián)合體 , 在同一個(gè)內(nèi)存地址上 , 既可以以 long 類型解析這塊數(shù)據(jù) , 也可以以 char 數(shù)組類型解析這塊數(shù)據(jù)union u {long val;char chars[sizeof(long)];} d;// 每次讀取 4 字節(jié) , 讀取次數(shù)為 nSize / 4j = nSize / 4;// 讀取最后不滿 4 個(gè)字節(jié)的數(shù)據(jù) remain = nSize % 4;// 寫(xiě)出數(shù)據(jù)準(zhǔn)備 laddr = pData;for (i = 0; i < j; i++) {// 準(zhǔn)備寫(xiě)出數(shù)據(jù) , 從 laddr 拷貝到 d.charsmemcpy(d.chars, laddr, 4);// 32 位的設(shè)備上 , 最長(zhǎng)只能讀取 4 字節(jié) ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);pDestAddr += 4;laddr += 4;}// 寫(xiě)出末尾不足 4 字節(jié)的數(shù)據(jù)部分 // 讀取的時(shí)候 , 如果不足 4 字節(jié) , 我們可以將數(shù)據(jù)直接讀取出來(lái) , 不影響程序運(yùn)行 // 寫(xiě)出的時(shí)候 , 如果寫(xiě)出數(shù)據(jù)不足 4 字節(jié) , 是 3 字節(jié) , 那么必須保證最后一位寫(xiě)出時(shí) , 不會(huì)出錯(cuò) , // 原來(lái)進(jìn)程中 第 4 位是什么數(shù)據(jù) , 寫(xiě)出去時(shí)也必須是同樣的數(shù)據(jù) , 否則進(jìn)程運(yùn)行出錯(cuò) if (remain > 0) {// 一次性必須寫(xiě)入 4 字節(jié) , 如果不足 4 字節(jié) , 先把數(shù)據(jù)讀取出來(lái) , 即讀取 4 字節(jié)出來(lái) d.val = ptrace(PTRACE_PEEKTEXT, m_nPid, (void*)pDestAddr, 0);// 假如數(shù)據(jù)有 3 字節(jié) , 那么就將上述讀取的 4 字節(jié)的前 3 個(gè)字節(jié)設(shè)置成我們要修改的數(shù)據(jù) // 這就保證了第 4 個(gè)字節(jié)不會(huì)出錯(cuò) for (i = 0; i < remain; i++) {d.chars[i] = *laddr++;}// 最后將最終的 4 字節(jié)數(shù)據(jù)ptrace(PTRACE_POKETEXT, m_nPid, (void*)pDestAddr, d.val);//整體寫(xiě)入}return PTERR_SUCCESS; }總結(jié)
以上是生活随笔為你收集整理的【Android 逆向】代码调试器开发 ( ptrace 函数 | 向进程内存写出数据 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 逆向】代码调试器开发
- 下一篇: 【Android 逆向】代码调试器开发