記錄這個問題的起因是,在hook時遇到了修改內容長度,超過原長度時,會出現顯示不全的問題。
比如把nexus 5改成nexus 100,只會顯示nexus 1。
所以去讀了下源碼
int __system_property_read(const prop_info *pi, char *name, char *value) { unsigned serial, len; for(;;) { serial = pi->serial; while(SERIAL_DIRTY(serial)) { __futex_wait((volatile void *)&pi->serial, serial, 0); serial = pi->serial; } len = SERIAL_VALUE_LEN(serial); memcpy(value, pi->value, len + 1); if(serial == pi->serial) { if(name != 0) { strcpy(name, pi->name); } return len; } } } int __system_property_get(const char *name, char *value) { const prop_info *pi = __system_property_find(name); if(pi != 0) { return __system_property_read(pi, 0, value); } else { value[0] = 0; return 0; } }
可以看到源碼中get調用了read來讀value,傳進去了find返回的指針,但是name給的是0,所以在read中沒法直接判斷讀的是哪個key,還是要hook get。
而長度的限制來自read內部的len實現,不能通過改參數的辦法修改,所以用了個別扭的方法先修改了read返回值的長度,再修改get的value,腳本如下:
Interceptor.attach(Module.findExportByName("libc.so", "__system_property_read"), { onEnter: function (args) { //sLog("__system_property_read onEnter " + Memory.readCString(args[0])); }, onLeave: function (retval) { //sLog(retval) retval.replace(0x5b);//修改read的返回值 } }); var str = "" var args2 = ""; Interceptor.attach(Module.findExportByName("libc.so", "__system_property_get"), { onEnter: function (args) { str = getStr(args[0]); args2 = ptr(args[1]); }, onLeave: function (retval) { if (str) { if (str.indexOf("ro.serialno") != -1) { var before = getStr(args2) putStr(args2, "05b3c6d30a280000") sLog(str + " " + before + " 改成 " + getStr(args2)); } } } });
其中hook read的返回值長度不是亂寫的,因為system_properties.h源碼中有限制最大長度
#define PROP_NAME_MAX 32 #define PROP_VALUE_MAX 92
hex(92) = '0x5c'
所以我把read的返回值改成了0x5b,減了1,肯定也夠用了。
源碼全文參考
https://android.googlesource.com/platform/bionic/+/0d787c1fa18c6a1f29ef9840e28a68cf077be1de/libc/bionic/system_properties.c
https://android.googlesource.com/platform/bionic/+/49f0a8f23bba188466c6ee3652858ef4da228c6f/libc/include/sys/system_properties.h