细说iOS代码签名(四)

导航

0x06 签名的校验

签名的校验并非一次性完成,在安装、启动、和运行时有着不同的校验规则。

Read on →
ios

细说iOS代码签名(三)

导航

0x05 CodeSign

万事具备,只欠东风,已经具备了签名所需的所有条件,接下来就可以开始研究签名的具体过程了。

Read on →
ios

细说iOS代码签名(二)

导航

0x03 开发者证书

在了解了签名和证书的基本结构之后,我们来研究一下iOS的开发者证书,它是开发过程中必不可少的东西,相信大家都有接触。众所周知,iOS设备并不能像Android那样任意地安装app,app必须被Apple签名之后才能安装到设备上。而开发者在开发App的时候需要频繁地修改代码并安装到设备上进行测试,不可能每次都先上传给Apple进行签名,因此需要一种不需要苹果签名就可以运行的机制。

Read on →
ios

细说iOS代码签名(一)

导航

0x01 签名的作用

数字签名其实跟我们手写的签名类似,代表一个特定的主体(签名者)对特定内容(被签名数据)的署名和认可,签名是对信息发送行为真实性的有效保障。数字签名在很多领域都有应用,iOS的代码签名正是其中最典型的一种,我们可以先尝试分析一下iOS上代码签名的目的和好处。

Read on →
ios

深度长文:细说iOS代码签名

0x00 前言

2008年苹果发布iOS2.0时引入了强制代码签名(Mandatory Code Signing)技术,为了能够严格控制设备上能够运行的代码,这为iOS设备的安全性和苹果的AppStore生态奠定了坚实的基础。作为iOSer总是要跟代码签名打交道的,相信大部分人对代码签名都是一知半解,本文将会由浅入深,深挖代码签名的内部细节。

导航

Read on →
ios

关于bitcode, 知道这些就够了

0x00 前言

苹果在WWDC 2015大会上引入了bitcode,随后在Xcode7中添加了在二进制中嵌入bitcode(Enable Bitcode)的功能,并且默认设置为开启状态。很多开发者在集成第三方SDK的时候都被bitcode坑过一把,然后google百度一番发现只要关闭bitcode就可以了,但是大部分开发者都不清楚bitcode到底是什么东西。这篇文档将给大家详细地介绍与bitcode有关的内容。

0x01 什么是bitcode

研究bitcode之前需要先了解一下LLVM,因为bitcode是由LLVM引入的一种中间代码(Intermediate Representation,简称IR),它是源代码被编译为二进制机器码过程中的中间表示形态,它既不是源代码,也不是机器码。从代码组织结构上看它比较接近机器码,但是在函数和指令层面使用了很多高级语言的特性。

LLVM是一套优秀的编译器框架,目前NDK/Xcode均采用LLVM作为默认的编译器。LLVM的编译过程可以简单分为3个部分:

图来自 http://www.aosabook.org/en/llvm.html
  1. 前端(Frontend),负责把各种类型的源代码编译为中间表示,也就是bitcode,在LLVM体系内,不同的语言有不同的编译器前端,最常见的如clang负责c/c++/oc的编译,flang负责fortran的编译,swiftc负责swift的编译等等
  2. 优化(Optimizer),负责对bitcode进行各种类型的优化,将bitcode代码进行一些逻辑等价的转换,使得代码的执行效率更高,体积更小,比如DeadStrip/SimplifyCFG
  3. 后端(Backend),也叫CodeGenerator,负责把优化后的bitcode编译为指定目标架构的机器码,比如X86Backend负责把bitcode编译为x86指令集的机器码

在这个体系中,不同语言的源代码将会被转化为统一的bitcode格式,三个模块可以充分复用,防止重复造轮子。如果要开发一门新的x语言,只需要造一个x语言的前端,将x语言的源代码编译为bitcode,优化和后端的事情完全不用管。同理,如果新的芯片架构问世,则只需要基于LLVM重新写一套目标平台的后端,非常方便。

0x02 bitcode初探

既然bitcode是代码的一种表示形式,因此它也会有自己的一套独立的语法,可以通过一个简单的例子来一探究竟,这里以clang为例,swift的操作和结果可能稍有不同。

本文所涉及的内容可以自行操作,也可以直接下载我写这篇文章时保存的副本

先编写一段helloworld代码(test.c):

1
2
3
4
5
#include <stdio.h>
int main(void) {
    printf("hello, world.\n");
    return 0;
}

通过以下命令可以将源代码编译为object文件:

1
2
3
$ clang -c test.c -o test.o
$ file test.o
test.o: Mach-O 64-bit object x86_64

其实,这个命令同时完成了前端、优化、后端三个部分,可以通过 -emit-llvm -c 将前端这一步单独拆出来,这样就可以看到bitcode了:

1
2
3
4
5
6
7
8
9
$ clang -emit-llvm -c test.c -o test.bc # 将源代码编译为bitcode
$ file test.bc
test.bc: LLVM bitcode, wrapper x86_64
$ clang -c test.bc -o test.bc.o # 将bitcode编译为object
$ file test.bc.o
test.bc.o: Mach-O 64-bit object x86_64
$ md5 test.bc.o test.o
MD5 (test.bc.o) = 70ea3a520c26df84d1f7ca552e8e6620
MD5 (test.o) = 70ea3a520c26df84d1f7ca552e8e6620

bitcode文件使用后缀名.bc表示,可以看到,将bitcode文件作为clang的输入,编出的object文件跟直接编源代码是相同的。然后在来看一下bitcode文件:

1
2
3
4
5
6
7
8
9
10
11
$ hexdump -C test.bc  | head
00000000  de c0 17 0b 00 00 00 00  14 00 00 00 08 0b 00 00  |................|
00000010  07 00 00 01 42 43 c0 de  35 14 00 00 07 00 00 00  |....BC..5.......|
00000020  62 0c 30 24 96 96 a6 a5  f7 d7 7f 4d d3 b4 5f d7  |b.0$.......M.._.|
00000030  3e 9e fb f9 4f 0b 51 80  4c 01 00 00 21 0c 00 00  |>...O.Q.L...!...|
00000040  74 02 00 00 0b 02 21 00  02 00 00 00 13 00 00 00  |t.....!.........|
00000050  07 81 23 91 41 c8 04 49  06 10 32 39 92 01 84 0c  |..#.A..I..29....|
00000060  25 05 08 19 1e 04 8b 62  80 10 45 02 42 92 0b 42  |%......b..E.B..B|
00000070  84 10 32 14 38 08 18 4b  0a 32 42 88 48 90 14 20  |..2.8..K.2B.H.. |
00000080  43 46 88 a5 00 19 32 42  04 49 0e 90 11 22 c4 50  |CF....2B.I...".P|
00000090  41 51 81 8c e1 83 e5 8a  04 21 46 06 51 18 00 00  |AQ.......!F.Q...|

通过hexdump可以看出这个文件并非文本文件,全是乱码,这样的文件是很难分析的。其实LLVM提供了llvm-dis/ llvm-as 两个工具,用于将bitcode在二进制格式和可读的文本格式之间进行相互的转化,但遗憾的是Xcode的编译器工具链中并没有附带这个命令,因此只能另寻他法。

Read on →
ios

Codegate 2017 2D Life Writeup

Description

2D Life

470 points

1
2
3
4
http://110.10.212.135:24135
http://110.10.212.135:24136
http://110.10.212.147:24135
http://110.10.212.147:24136

I didn’t have enough time to solve this challenge since I’m busy at work. It’s a pity that my team didn’t, neither. But I have to say it’s a very challenging one. Combination of crypto and SQL injection.

First Sight

It seemed to be a web challenge because the entrance was a website. So let’s start with HTTP requests and responses. In the source code of the page, a path to secret login page was commented.

1
2
3
4
5
6
7
8
9
<div id="navbar" class="navbar-collapse collapse">
  <ul class="nav navbar-nav">
  <li><a href="/">Home</a></li>
  <li><a href="?p=pic">Pictures</a></li>
  <li><a href="?p=music">Music</a></li>
  <li><a href="?p=contact">Contact</a></li>
  <!--<li><a href="?p=secret_login">Login</a><li>-->
  </ul>
</div>

The login page set a cookie like this(using httpie)

1
2
3
4
5
6
7
8
9
10
11
$ http http://110.10.212.135:24135/\?p\=secret_login
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Length: 579
Content-Type: text/html; charset=UTF-8
Date: Fri, 10 Feb 2017 05:57:50 GMT
Keep-Alive: timeout=5, max=100
Server: Apache/2.4.18 (Ubuntu)
Set-Cookie: identify=t93ZpEcFoz4%3D%7C6uDGkD5VtEk0H9kAOzOrQECDzRdVuuDYn4h8ISoWSUuetH5Cb%2BBgSfxSd9WfX9RxHGC7cnAZdnmxqneZrLkQ%2Bw%3D%3D
Vary: Accept-Encoding

It’s easy to say that the cookie is two parts of base64 encoded string concatenated by a |.

1
t93ZpEcFoz4=|6uDGkD5VtEk0H9kAOzOrQECDzRdVuuDYn4h8ISoWSUuetH5Cb+BgSfxSd9WfX9RxHGC7cnAZdnmxqneZrLkQ+w==

Different cookies was returned when repeating the same request. Modify the tail of the cookie will got a message Error has occur from decrypt.., but the head won’t.

Read on →

我的玩具——乐高魔方机器人

视频预览

优酷视频:

Youtube:

0x00 简要说明

硬件环境:Lego NXT 8547, iPhone 4S(需越狱)

软件依赖:LeJOS, BTStack, OpenCV2

还原效率:扫描10~15秒,计算<1秒,还原~1分钟

GithubiOS控制器 Lego机器人

Read on →

Proxy Server Crawler

When we are doing security tests, we always change our IP address to bypass some security strategies. The easiest way to change IP is using a proxy.

Some websites can provide proxy IPs, but none of them can ensure the healthy of those proxy hosts. It’s a horrible thing to check them one by one by hand when you wanna got one. So we can crawl these websites and test every proxy IP automatically.

The project is hosted at https://github.com/xelzmm/proxy_server_crawler.

Introduction

Proxy Server Crawler is a tool used to crawl public proxy servers from proxy websites. When crawled a proxy server(ip::port::type), it will test the functionality of the server automatically.

Currently supported websites:

Currently supported testing(for http proxy)

  • ssl support
  • post support
  • speed (tested with 10 frequently used sites)
  • type(high/anonymous/transparent)
Read on →

iOS代码混淆

标识符混淆

念大婶在博客中介绍了两种方法,用于保护代码逻辑,对抗逆向分析

  • 代码混淆 通过宏定义,混淆objective-c消息(函数),用于对抗class-dump。
  • 敏感逻辑用C实现 通过static关键字和函数指针的方式,将关键逻辑隐藏,可以对抗class-dump和Cycript攻击。

如果用了第二种方式,将函数改用c实现,虽然通过class-dump得不到有价值的信息,但通过nm命令或者IDA/Hopper等工具仍然能从符号表中找到这些c函数以及衍生出的一些静态变量。针对这种情况,我们还是可以通过宏定义的方式,将这些c的标识符(函数名、变量名)替换为随机字符串。

举个例子:

1
2
3
4
5
6
7
8
9
#define func1 gtBFTcseXSElp
#define func2 yNGYcdrCDEzaqZAQki
#define globalValue uNHUvfrVFRxawXAWlo
int globalValue;
void func1() {
}
void func2(int i) {
    func1();
}

nm检查符号表,结果如下

1
2
3
0000000000000000 T _gtBFTcseXSElp
0000000000000004 C _uNHUvfrVFRxawXAWlo
0000000000000010 T _yNGYcdrCDEzaqZAQki

说明宏替换对于c的标识符同样有效。但是要一个个手动去define,感觉是要累死的节奏。如果能通过一个脚本,自动从源代码里把所有的标识符声明提取出来,生成一个头文件就好了。可以考虑几种方案:

  1. 使用正则表达式,根据标识符的声明语法提取
  2. 先解析为语法树,再提取标识符节点
  3. 给需要混淆的符号打个标记

很显然,前两种方案都很繁琐,不好维护。并且如果我要做一个library给第三方使用,必然要暴露一些接口不能被混淆,只有第三种方式可以灵活地选择那些需要混淆哪些不需要,而这种方案实现起来也最简单。最终实现如下:

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
//test.c

#ifdef SYMBOL_OBFUSCATE // 通过外部宏定义控制是否混淆

#include "symbols.h"  // 引入生成的混淆头文件
#define SYMBOL(name) asm(name) // 使用asm label语法修改符号名称

#else 

#define SYMBOL(name)  // 将宏定义为空,即不混淆

#endif

// 声明并标记需要混淆的符号
int globalValue SYMBOL(_globalValue);
void func1() SYMBOL(_func1);
void func2(int a) SYMBOL(_func2);
void func3();    // 不混淆

// 以下不需要做任何处理,保持原样即可
void func1() {

}


void func2(int a) {
    func1();
}

void func3() {

}

使用asm label语法的好处是,只需要将符号的声明标记出来进行替换即可, 不需要对该符号的引用进行标记和替换。如果要混淆已经完成的代码,这一点非常省时省力。

Read on →