于是今天看到有人在问使用 THEOS 来 hook 带有汉字的 Objective-C 的方法时会有类似如下的报错。
$ make > Making all for tweak UnicodeHook… ==> Preprocessing Tweak.xm… ==> Compiling Tweak.xm (armv7)… Tweak.xm:3:1: error: missing context for method declaration - (id)中文方法名 { ^ 1 error generated.
于是研究了 THEOS 的源代码,给出了一个简单的解决办法,不仅可以 Hook 带有汉字的方法,带有日文、阿拉伯文等等的方法 / Objective-C 类,只要这些 identifier 在 Objective-C 的语法规则中被认可,那就都可以被 Hook。而且在写 %group 的时候也可以使用除 ACSII 以外的文字了。
THEOS 的语法是 Logos,而 Logos 是用 Perl 写的,
那么直接看 Logos 处理 xm 过程吧,文件是 theos/bin/logos.pl。定位到第 324 行,这里就是处理 "- (id)中文方法名 {" 的地方。
...... } elsif($currentClass && $line =~ /\G([+-])\s*\(\s*(.*?)\s*\)(?=\s*[\$_\w])/gc && $directiveDepth < 1) { # [+-] (<return>)<[X:]>, but only when we're in a %hook. ......
可以看到正则表达式只允许了'$', '_', 以及由 ASCII 可打印字符所组成的 words,于是这里要想让汉字和其他理论上可行的 Unicode 字符通过正则表达式就可以了。
鉴于不同语言的字符在不同区域,要精确控制并不方便,考虑到平时写 Hook 的时候也不会随意写上什么字符,于是我将这里的规则改为如下(注意下面绿色背景高亮的部分)
...... } elsif($currentClass && $line =~ /\G([+-])\s*\(\s*(.*?)\s*\)(?=\s*[^\s])/gc && $directiveDepth < 1) { # [+-] (<return>)<[X:]>, but only when we're in a %hook. ......
在这上面还有其他的几个判断规则,从上到下分别是匹配
- %hook <identifier>
- %subclass <identifier> : <identifier> \<<protocols ...>\>
- %group <identifier>
- %class [+-]<identifier>
- %c([+-]<identifier>)
于是把它们的匹配规则一并改了。
...... if($line =~ /\G%hook\s+([^\s]+)/gc) { # "%hook <identifier>" ...... } elsif($line =~ /\G%subclass\s+([^\s]+)\s*:\s*([^\s]+)\s*(\<\s*(.*?)\s*\>)?/gc) { # %subclass <identifier> : <identifier> \<<protocols ...>\> ...... } elsif($line =~ /\G%group\s+([^\s]+)/gc) { # %group <identifier> ...... } elsif($line =~ /\G%class\s+([+-])?([^\s]+)/gc) { # %class [+-]<identifier> ...... } elsif($line =~ /\G%c\(\s*([+-])?([^\s]+)\s*\)/gc) { # %c([+-]<identifier>) ...... } ......
这样调整之后,就可以在 %hook, %subclass, %group, %class 和 %c 的对应的地方使用 Unicode 字符了,使用效果如下
使用 Hopper 反编译对应的 dylib 也可以看到
于是你可以考虑自己手动改,也可以去 git clone 我的修改过的 theos,theos。