編輯:關於Android編程
通過取系統時間,檢測關鍵代碼執行耗時,檢測單步調試,類似函數有:time,gettimeofday,clock_gettime.
也可以直接使用匯編指令RDTSC讀取,但測試ARM64有兼容問題。
time_t t1, t2;
time (&t1);
/* Parts of Important Codes */
time (&t2);
if (t2 - t1 > 2) {
puts ("debugged");
}
進程的狀態信息能通過 procfs 系統反饋給用戶空間,調試會使進程狀態發生變化:
char file [PATH_LEN];
char line [LINE_LEN];
snprintf (file, PATH_LEN-1, "/proc/%d/status", pid);
FILE *fp = fopen (file, "r");
while (fgets (line, LINE_LEN-1, fp)) {
if (strncmp (line, "TracerPid:", 10) == 0) {
if (0 != atoi (&line[10])) {
/* encrypt random .TEXT code */
}
break;
}
}
fclose (fp);
類似可以檢測的接口還有:
/proc/pid/status /proc/pid/task/pid/status /proc/pid/stat /proc/pid/task/pid/stat /proc/pid/wchan /proc/pid/task/pid/wchan
ARM程序下斷點,調試器完成兩件事:
當命中斷點時,系統產生SIGTRAP信號,調試器收到信號後完成下面操作:
這時當控制權回到被調試程序時,正好執行斷點位置指令。這就是 ARM 平台斷點的基本原理。
可以看到,斷點是通過處理 SIGTRAP 信號來實現的,假如我們自己注冊 SIGTRAP 的信號處理函數,並在程序中主動執行中斷指令觸發中斷。
在中斷處理函數中,NOP 掉斷點指令,程序可正常執行。但在調試狀態下,調試器遇到斷點指令時,會去恢復原先指令,由於不是調試器下的斷點,所以恢復會失敗,而調試器會繼續第2步操作,回退PC寄存器,程序會在此處無限循環。
斷點會替換內存中原有指令,因此通過檢測內存中的斷點指令,可以檢測調試:
#include <stdlib.h>
#include <stdio.h>
#include <elf.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
void checkBreakPoint ();
unsigned long getLibAddr (const char *lib);
#define LOG_TAG "ANTIDBG_DEMO"
#include <android log.h="">
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
int main ()
{
dlopen ("./libdemo.so", RTLD_NOW);
sleep (60);
checkBreakPoint ();
return 0;
}
unsigned long getLibAddr (const char *lib)
{
puts ("Enter getLibAddr");
unsigned long addr = 0;
char lineBuf[256];
snprintf (lineBuf, 256-1, "/proc/%d/maps", getpid ());
FILE *fp = fopen (lineBuf, "r");
if (fp == NULL) {
perror ("fopen failed");
goto bail;
}
while (fgets (lineBuf, sizeof(lineBuf), fp)) {
if (strstr (lineBuf, lib)) {
char *temp = strtok (lineBuf, "-");
addr = strtoul (temp, NULL, 16);
break;
}
}
bail:
fclose(fp);
return addr;
}
void checkBreakPoint ()
{
int i, j;
unsigned int base, offset, pheader;
Elf32_Ehdr *elfhdr;
Elf32_Phdr *ph_t;
base = getLibAddr ("libdemo.so");
if (base == 0) {
LOGI ("getLibAddr failed");
return;
}
elfhdr = (Elf32_Ehdr *) base;
pheader = base + elfhdr->e_phoff;
for (i = 0; i < elfhdr->e_phnum; i++) {
ph_t = (Elf32_Phdr*)(pheader + i * sizeof(Elf32_Phdr)); // traverse program header
if ( !(ph_t->p_flags & 1) ) continue;
offset = base + ph_t->p_vaddr;
offset += sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * elfhdr->e_phnum;
char *p = (char*)offset;
for (j = 0; j < ph_t->p_memsz; j++) {
if(*p == 0x01 && *(p+1) == 0xde) {
LOGI ("Find thumb bpt %p", p);
} else if (*p == 0xf0 && *(p+1) == 0xf7 && *(p+2) == 0x00 && *(p+3) == 0xa0) {
LOGI ("Find thumb2 bpt %p", p);
} else if (*p == 0x01 && *(p+1) == 0x00 && *(p+2) == 0x9f && *(p+3) == 0xef) {
LOGI ("Find arm bpt %p", p);
}
p++;
}
}
}
inotify 是一個內核用於通知用戶態文件系統變化的機制,當文件被訪問,修改,刪除等時用戶態可以快速感知。
1.使用 inotify_init() 初始化一個 inotify 實例並返回文件描述符,每個文件描述符都關聯了一個事件隊列:
int fd = inotify_init ();
2.拿到這個文件描述符後下一步就告訴內核,哪些文件發生哪些事件時你得通知我,通過函數 inotify_add_watch 實現:
int wd = inotify_add_watch (fd, path, mask);
第一個參數即 inotify_init 返回的文件描述符,path 表示關注的目標路徑,可以是文件目錄等。mask 表示關注的事件的掩碼,如 IN_ACCESS 代表訪問,IN_MODIFY 代表修改等
相應的,可以通過 inotify_rm_watch 來刪除一個watch:
int ret = inotify_rm_watch (fd, wd);
這樣,每當監視的文件發生變化時,內核便給 fd 關聯的事件隊列裡面塞一個文件事件。文件事件用一個 inotify_event 結構表示,可以通過 read 來讀取:
struct inotify_event {
__s32 wd; /* watch descriptor */
__u32 mask; /* watch mask */
__u32 cookie; /* cookie to synchronize two events */
__u32 len; /* length (including nulls) of name */
char name[0]; /* stub for possible name */
};
size_t len = read (fd, buf, LEN);
通過監視/proc/pid/maps文件的打開事件,可防針對 360 加固的 dump 脫殼
文件變化與事件觸發非必然聯系,例如/proc/pid/status中的TracerPid值在被調試時是變化的,但其變化沒有事件發生,原因未知可能與 inofity 的內核實現有關
ptrace() 是 Linux 的一個系統調用,也是 Linux 下 gdb 等調試器實現的基礎。它提供了 Linux 下一個進程跟蹤另一個進程寄存器、內存等的能力。
由於 ptrace() 到一個線程後,任何信號都將導致線程STOP 並將控制權交由調用者 ,因此如果利用每個線程只能有一個ptrace跟蹤 來防止附加的話,需要處理好這個關系:
while (waitpid (g_childPid, &stat, 0) ) {
if (WIFEXITED (stat) || WIFSIGNALED(stat)) {
XXX_DEBUG_LOG ("waitpid : child died\n");
exit (11);
}
ptrace (PTRACE_CONT, g_childPid, NULL, NULL);
}
Android 事件分發機制探析
一基礎知識 android的事件處理分為3步。 1)public booleandispatchTouchEvent(MotionEvent ev) 這個方法用來分發
設計模式之命令模式(Command)摘錄
23種GOF設計模式一般分為三大類:創建型模式、結構型模式、行為模式。創建型模式抽象了實例化過程,它們幫助一個系統獨立於如何創建、組合和表示它的那些對象。一個類創建型模式
Android源碼解析ViewGroup的touch事件分發機制
概述本篇是繼上一篇Android 源碼解析View的touch事件分發機制之後的,關於ViewGroup事件分發機制的學習。同樣的,將采用案例結合源碼的方式來進行分析。前
Android自定義View獲取注冊驗證碼倒計時按鈕
在Android開發中,我們不可避免的會做到注冊功能,而現在的注冊大多數都是用手機去注冊的,那麼注冊的時候都會要求用獲取驗證碼的方式去驗證,我們接下來就來實戰一下自定義獲