首页
社区
课程
招聘
[原创]hook之函数栈帧追溯、NSLog捕获、STDOUT重定向
发表于: 2013-12-31 00:29 11726

[原创]hook之函数栈帧追溯、NSLog捕获、STDOUT重定向

2013-12-31 00:29
11726

栈帧的追溯需要用到函数:
int backtrace(void**,int);
char** backtrace_symbols(void* const*,int);
用法和linux上一样,参考:http://man7.org/linux/man-pages/man3/backtrace.3.html
例如可以把追溯功能放到我的hook程序里:
FILE *my_fopen(const char *path, const char *mode)
{
FILE *fp;
void *buffer[100];
char **strings;
int nptrs, j;

fp = org_fopen(path, mode);
log_progress(“fopen(%s, %s)=%08x\n”, path, mode, fp);
nptrs = backtrace(buffer, 100);
strings = (char **)backtrace_symbols(buffer, nptrs);
if (strings == NULL)
return fp;
for (j = 0; j < nptrs; j++)
log_progress(“%s\n”, strings[j]);
free(strings);
return fp;
}
在动态库初始化的时候挂接hook点:
MSHookFunction(fopen, my_fopen, (void **)&org_fopen);
看到的效果如下:
=====================================================================================================
fopen(/var/mobile/Applications/39809BB6-96CE-4DE5-8701-44B3AB7738D2/tdbeta.app/Data/unity default resources, rb)=012e224c
0   testlib.dylib                       0x011fa95c my_fopen + 100
1   tdbeta                              0x00afe5b8 tdbeta + 11523512
2   tdbeta                              0x00afe8d4 tdbeta + 11524308
3   tdbeta                              0x00ae9a48 tdbeta + 11438664
4   tdbeta                              0x00ae9ad8 tdbeta + 11438808
5   tdbeta                              0x00aef7a4 tdbeta + 11462564
6   tdbeta                              0x00aeaeb8 tdbeta + 11443896
7   tdbeta                              0x00aec688 tdbeta + 11449992
8   tdbeta                              0x009a5538 tdbeta + 10110264
9   tdbeta                              0x00abb7f0 tdbeta + 11249648
10  tdbeta                              0x009c6c74 tdbeta + 10247284
11  tdbeta                              0x00ac0710 tdbeta + 11269904
12  tdbeta                              0x00ab242c tdbeta + 11211820
13  tdbeta                              0x008f0190 tdbeta + 9367952
14  tdbeta                              0x000047dc tdbeta + 14300
15  Foundation                          0×32591277 <redacted> + 450
16  CoreFoundation                      0x31c585df <redacted> + 14
17  CoreFoundation                      0x31c58291 <redacted> + 272
18  CoreFoundation                      0x31c56f01 <redacted> + 1232
19  CoreFoundation                      0x31bc9ebd CFRunLoopRunSpecific + 356
20  CoreFoundation                      0x31bc9d49 CFRunLoopRunInMode + 104
21  GraphicsServices                    0x357a02eb GSEventRunModal + 74
22  UIKit                               0x33adf301 UIApplicationMain + 1120
23  spad.dylib                          0x0138b807 _Z21new_UIApplicationMainiPPcP8NSStringS2_ + 238
24  tdbeta                              0×00005014 tdbeta + 16404
25  tdbeta                              0x00003bf8 tdbeta + 11256

如何记录NSLog函数的输出?
首先看NSLog函数的调用关系:
NSlog->_CFLogvEx->0x32262f20
_CFLogvEx调用:
CFStringCreateWithFormatAndArgumentsAux
CFStringGetLength
CFStringGetMaximumSizeForEncoding
进行字符串格式化,然后malloc一块内存通过CFStringGetCString写入
函数0x32262f20调用:
CFAbsoluteTimeGetCurrent获得系统时间
CFGetProgname获得mach-o文件名
getpid获得进程pid
然后重点来了:
0x32263250 <<redacted>+816>:    movs    r0, #2
0x32263252 <<redacted>+818>:    blx     0x322b541c <dyld_stub_writev>
没错,写入文件句柄2,也就是stderr
writev执行完之后,可以在stderr上看到格式化好的字符串,例如:
2013-12-30 23:57:29.292 tdbeta[835:907] -> registered mono modules 0xf9b580

结论:要获得NSLog输出的信息只需要重定向stderr

如何做重定向?
重定向只需要创建一个文件,然后将其句柄通过函数dup2传入,替换掉默认的句柄就好了。
将下面代码放到动态库init函数里,然后去看这个log文件吧。
int substrateInit(void)
{
        int fd;
        char pathBuffer[BUFSIZE];
        fflush(stdout);
        fflush(stderr);
        snprintf(pathBuffer, sizeof(pathBuffer), "%s/Library/stdout-%li.log", getenv("HOME"), time(NULL));
        setvbuf(stdout,NULL,_IONBF,0);
        fd = open(pathBuffer, (O_RDWR | O_CREAT), 0644);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        printf("Here is dll init, redirect stdout and stderr to logfile\n");
        return 0;
}


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 5
支持
分享
最新回复 (2)
雪    币: 14
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
哥们看来是从UNIX,LINUX转过来的,功力看来很深厚啊,向你学习!
但是,函数栈帧追溯在iOS中有一种更简单的方法,就是[NSThread callStackSymbols],backtrace_symbols是OSX文档中的,如果用在App Store中不知会不会被拒
2014-3-8 22:18
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这哥们应该还做win的。句柄这翻译都是搞windows的,哈哈
2014-3-12 09:35
0
游客
登录 | 注册 方可回帖
返回
//