Tweak简介
不知道Tweak这个单词如何翻译过来中文 >_< 。逆向工程里面一般用Tweak描述一种程序,能够在越狱环境下,利用runtime特性,对App的功能进行某种增强(或者做坏事)。基本原理是hook住目标类,替换目标函数或者增加新的函数,然后完成新的逻辑。
基本套路
根据前一篇文章的套路,可以实现一个SpringBoard的Tweak。这次我们拿一个商业App来进行分析。实际上,逆向需要配合很多分析理解,寻找到关键的函数入口,这方面的内容不是简单几句话能够讲清楚的。本文重点在于如何写tweak,故暂时理解为,本人已经知道了目标类和目标函数,现在想要hook住它并且做一些事情。
//
// Generated by class-dump 3.5 (64 bit).
//
// class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//
#import "NSObject.h"
@class NSError, NSString;
@interface ImageProcessProgram : NSObject
{
_Bool _compiled;
_Bool _linked;
NSString *_vshString;
NSString *_fshString;
unsigned int _vShader;
unsigned int _fShader;
_Bool _readyToUse;
unsigned int _program;
NSError *_error;
}
@property(readonly, nonatomic) unsigned int program; // @synthesize program=_program;
@property(readonly, nonatomic) _Bool readyToUse; // @synthesize readyToUse=_readyToUse;
@property(readonly, copy, nonatomic) NSError *error; // @synthesize error=_error;
- (void).cxx_destruct;
- (_Bool)use;
- (_Bool)link;
- (_Bool)compile;
- (id)initWithVertexShaderString:(id)arg1 fragmentShaderString:(id)arg2;
@end
以上是一个加载OpenGL shader的类。假设现在我想知道,某一个图像滤镜究竟加载了什么样的一个shader,就可以通过hook住这个类的某一个函数,然后在函数里print出类的私有变量。
/*
Hook into LoginRegisterViewController as to check if the tweak works or not.
*/
%hook LoginRegisterViewController
-(void)viewDidAppear:(id)animated
{
%orig;
%log;
[self performSelector:@selector(snapchatterButtonClicked) withObject:nil afterDelay:1];
}
%new
-(void)showAlertView
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Hello World" message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
%end
/*
Hook into ImageProcessProgram in order to check the vshString and the fshString
*/
%hook ImageProcessProgram
- (id)compile
{
id fshaderString;
id vshaderString;
object_getInstanceVariable(self, "_fshString", (void**)&fshaderString);
object_getInstanceVariable(self, "_vshString", (void**)&vshaderString);
%log(@"---------------- Hello World! --------------");
NSLog(@"vertexShader: %@", vshaderString);
NSLog(@"fragmentShader: %@", fshaderString);
%log(@"---------------- End of printing -----------");
return %orig;
}
%end
上述例子是钩住compile函数,除了使用%orig
调用原来函数内容之外,还可以加上%log
或者%log(@"something")
从而打印系统日志。在上述例子,为了获得变量,我们使用
id someVariable
object_getInstanceVariable(self, "variableName", (void**)&someVariable)
// use someVariable to do sometihng
来获得变量。然后可以用于print。
更简单的做法
对于比较简单的需求,例如只是想快速查看某个对象的一些属性,或者想快速查看某个函数的作用,其实并不需要用到tweak这种强大的武器。毕竟,我们为了看一个属性,就写一个tweak,那么也太奢侈了些。事实上,我们拥有一个非常强大的工具,由saurik大神倾情奉献,名为
cycript
顺手给出三个重要的链接,其实google一下也可以搜到。
- http://www.cycript.org
- http://iphonedevwiki.net/index.php/Cycript
- http://iphonedevwiki.net/index.php/Cycript_Tricks#Getting_bundle_identifier
参照着给出了例子,我们摸索着可以实现和上述tweak一样的目的。
首先常规的ssh到越狱机上(使用usbmux)
~# python tcprelay.py -t 22:2222
然后打开另一个command window,ssh到机器
root# ssh root@localhost -p 2222
root@localhost's password:
root# cycript -p TargetAppName
cy# choose(ImageProcessProgram)
[#"<ImageProcessProgram: 0x15f14a360>",#"<ImageProcessProgram: 0x15f14aff0>",#"<ImageProcessProgram: 0x15f14c3b0>"]
cy# var program = new Instance("0x15f14c3b0")
#"<ImageProcessProgram: 0x15f14c3b0>"
cy# program->_vshString
@"attribute vec4 position; attribute vec4 inputTextureCoordinate; varying vec2 textureCoordinate; void main() { gl_Position = position; textureCoordinate = inputTextureCoordinate.xy; }"
cy# program->_fshString
@"precision highp float; varying vec2 textureCoordinate; uniform sampler2D inputImageTexture; uniform sampler2D toneCurveTexture; const highp vec3 W = vec3(0.2125, 0.7154, 0.0721); void main() { lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate); lowp float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r; lowp float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g; lowp float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b; lowp vec4 toneColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a); float luminance = dot(toneColor.rgb, W); gl_FragColor = vec4(vec3(luminance), textureColor.a); }"
choose用于快速定位到内存中正在运行的实例对象。找到内存地址后,可以通过Instance赋值到一个变量上,然后私有变量用->,属性用. 就可以查看各种对象属性啦~cycript还有更强大的作用,用得好不比写tweak弱,例如也可以实现method swizzle等,不过需要更深入的摸索噜。