盒子
盒子
文章目录
  1. 一. 识别二维码
  2. 二. 解码字符串
  3. 三. 保存账号信息

Mac下对ShadowsocksX进行Hook,实现自动更新账号

使用ShadowsocksX的人群有两种,第一种自己购买的账号,第二种就是在网上找临时的账号,但临时账号,过几小时,密码都会改变,又得重新找开网站,重新设置。今天就针对这种情况对ShadowsocksX进行Hook,达到启动APP后,自动更新账号密码的目的。
编写工具为EasySIMBL
一. 识别二维码

二. 解码字符串

三. 保存账号信息


一. 识别二维码

class_dump导出头文件后,你会发现里面有Zxing二维码扫描框架,那我们就直接使用Zxing来进行二维码识别,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
+ (NSString *)scanQRCodeWithImage:(NSImage *)image {
if (image == nil) {
return nil;
}
CGImageRef imageToDecode = [VPNHelper nsImageToCGImageRef:image];
ZXLuminanceSource *source = [[objc_getClass("ZXCGImageLuminanceSource") alloc] initWithCGImage:imageToDecode];
ZXBinaryBitmap *bitmap = [objc_getClass("ZXBinaryBitmap") binaryBitmapWithBinarizer:[objc_getClass("ZXHybridBinarizer") binarizerWithSource:source]];
ZXDecodeHints *hints = [objc_getClass("ZXDecodeHints") hints];
ZXMultiFormatReader *reader = [objc_getClass("ZXMultiFormatReader") reader];
ZXResult *result = [reader decode:bitmap
hints:hints
error:nil];
if (result) {
return result.text;
} else {
return nil;
}
}

扫描得到的信息为’ss://cmM0LW1kNToyMDQ2NzIzMkAxMzguNjguNjEuNDI6MjM0NTY=’

二. 解码字符串

由于ShadowsocksX可以生成二维码,那就去查找在哪生成的二维码。在所有.h文件中,搜索qrcode后,在SWBAppDelegate.h文件中找到 showQRCode方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void -[SWBAppDelegate showQRCode](void * self, void * _cmd) {
r12 = self;
rax = [ShadowsocksRunner generateSSURL]; // 生成二维码URL
rax = [rax retain];
if (rax != 0x0) {
var_30 = rax;
rax = [SWBQRCodeWindowController alloc];
rax = [rax initWithWindowNibName:@"QRCodeWindow"];
rdi = r12->qrCodeWindowController;
r12->qrCodeWindowController = rax;
[rdi release];
var_38 = r12->qrCodeWindowController;
rbx = [[var_30 absoluteString] retain];
[var_38 setQrCode:rbx];
[rbx release];
[r12->qrCodeWindowController showWindow:r12];
[*_NSApp activateIgnoringOtherApps:0x1];
rbx = [[r12->qrCodeWindowController window] retain];
[rbx makeKeyAndOrderFront:0x0];
[rbx release];
rax = var_30;
}
[rax release];
return;
}

不难发现,[ShadowsocksRunner generateSSURL]生成二维码字符串,那我们继续

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void * +[ShadowsocksRunner generateSSURL](void * self, void * _cmd) {
rax = [ShadowsocksRunner isUsingPublicServer];
rbx = 0x0;
if (rax == 0x0) {
r15 = [[ShadowsocksRunner configForKey:@"proxy encryption"] retain];
var_38 = r15;
r13 = [[ShadowsocksRunner configForKey:@"proxy password"] retain];
rbx = [[ShadowsocksRunner configForKey:@"proxy ip"] retain];
rax = [ShadowsocksRunner configForKey:@"proxy port"];
rax = [rax retain];
var_40 = rax;
stack[2048] = rax;
rcx = r15;
r12 = r13;
r15 = rbx;
rbx = [[NSString stringWithFormat:@"%@:%@@%@:%@", rcx, r12, r15, stack[2048]] retain];
var_30 = rbx;
[var_40 release];
[r15 release];
[r12 release];
[var_38 release];
rdi = rbx;
r14 = [[rdi dataUsingEncoding:0x4] retain];
r15 = [[r14 base64Encoding] retain];
[r14 release];
r12 = [[NSString stringWithFormat:@"ss://%@", r15] retain];
rbx = [[NSURL URLWithString:r12] retain];
[r12 release];
[r15 release];
[var_30 release];
}
rdi = rbx;
rax = [rdi autorelease];
return rax;
}

从代码中可以看出,该方法对账号的地址,端口,密码,加密方式进行拼接,然后Base64编码。

三. 保存账号信息

既然有了账号信息,剩下的就是将该信息存储,我们知道ShadowsocksX有个服务器设定页面,不难想象,该类里肯定有对账号进行增删改查的功能,用Interface Inspector(Mac下的UI查看工具,相当于iOS的Reveal)工具可知服务器设定页面属于SWBConfigWindowController类,在该类中,我们发现了-(void)OK:(id)arg1;,该方法是在我们修改信息后,点击确定所执行的方法,那我们支看看这里都做了什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void -[SWBConfigWindowController OK:](void * self, void * _cmd, void * arg2) {
rbx = self;
if ([self saveCurrentProfile] != 0x0) {
[rbx saveSettings];
r14 = [[rbx window] retain];
[r14 performClose:rbx];
rdi = r14;
[rdi release];
}
else {
rdi = rbx;
[rdi shakeWindow];
}
return;
}

该方法简单来说调用了两个重要方法saveCurrentProfile和saveSettings,saveCurrentProfile方法只是把当前修改的账号信息保存,这方法我们忽略,重点来看看saveSettings方法。

1
2
3
4
5
6
7
8
9
10
oid -[SWBConfigWindowController saveSettings](void * self, void * _cmd) {
rdx = self->configuration;
[ProfileManager saveConfiguration:rdx];
[ShadowsocksRunner reloadConfig];
rbx = [[self delegate] retain];
[rbx configurationDidChange];
rdi = rbx;
[rdi release];
return;
}

由代码可知,保存账号信息调用了[ProfileManager saveConfiguration:rdx];和[ShadowsocksRunner reloadConfig];那我们只要手动的调用这两方法就可以了。我的实现代码如下:

1
2
3
4
5
6
Profile *profile = [self initProfileWithURL:url]; // 账号的Model
Configuration *configuration = [objc_getClass("ProfileManager") performSelector:@selector(configuration)];
configuration.profiles = [@[profile] mutableCopy];
configuration.current = 0;
[objc_getClass("ProfileManager") saveConfiguration:configuration];
[objc_getClass("ShadowsocksRunner") reloadConfig];

由于该方法是异步,所以最后我们再调用下面方法刷新服务器列表

1
2
SWBAppDelegate *appDelegate = [NSApplication sharedApplication].delegate;
[appDelegate valueForKey:@"updateServersMenu"];

In the end !

原创文章如需转载,请注明出处。

关注我
扫一扫,关注我