-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ade89f1
Showing
20 changed files
with
4,208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
(The MIT License) | ||
|
||
Copyright (c) 2020 neilwu (https://github.com/neil-wu) | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
'Software'), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
### FridaHookSwiftAlamofire | ||
|
||
A frida tool that capture GET/POST HTTP requests of iOS Swift library 'Alamofire' and disable SSL Pinning. | ||
|
||
### Features | ||
|
||
* Capture and print GET/POST HTTP requests in Alamofire | ||
* Kill SSL Pinning in Alamofire | ||
* Swift runtime interop in Frida (Support Swift Foundation URL/Data/String) | ||
* Support Swift 5.* | ||
* Demo code for calling swift runtime function `Foundation.Data._bridgeToObjectiveC()` | ||
|
||
![demo](./doc/demo.png) | ||
|
||
|
||
#### Usage | ||
|
||
1. build frida-agent (npm install && npm run watch) | ||
2. ./run.sh or frida -UF -l ./frida-agent/_agent.js | ||
|
||
#### License | ||
|
||
MIT | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/_agent.js | ||
/node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
### How to compile & load | ||
|
||
```sh | ||
$ git clone git://github.com/oleavr/frida-agent-example.git | ||
$ cd frida-agent-example/ | ||
$ npm install | ||
$ frida -U -f com.example.android --no-pause -l _agent.js | ||
``` | ||
|
||
### Development workflow | ||
|
||
To continuously recompile on change, keep this running in a terminal: | ||
|
||
```sh | ||
$ npm run watch | ||
``` | ||
|
||
And use an editor like Visual Studio Code for code completion and instant | ||
type-checking feedback. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { log } from "./logger"; | ||
|
||
function attach() { | ||
try { | ||
// Disable Alamofire ServerTrust policy | ||
// SessionDelegate func attemptServerTrustAuthentication(with challenge: URLAuthenticationChallenge) -> ChallengeEvaluation | ||
// Alamofire.SessionDelegate.attemptServerTrustAuthentication(with: __C.NSURLAuthenticationChallenge) -> (disposition: __C.NSURLSessionAuthChallengeDisposition, credential: __C.NSURLCredential?, error: Alamofire.AFError?) | ||
let func_attemptServerTrust = Module.getExportByName(null, '$s9Alamofire15SessionDelegateC32attemptServerTrustAuthentication4withSo36NSURLSessionAuthChallengeDispositionV11disposition_So15NSURLCredentialCSg10credentialAA7AFErrorOSg5errortSo019NSURLAuthenticationK0C_tF'); // remove prefix _ | ||
log(`[HookAFServerTrust] hook func_attemptServerTrust ${func_attemptServerTrust}`); | ||
Interceptor.attach(func_attemptServerTrust, { | ||
onLeave(retval:InvocationReturnValue) { | ||
// force set retval to 0x1 to enable .performDefaultHandling | ||
|
||
let val = retval.toInt32(); | ||
if (val != 0x1) { | ||
log(`[HookAFServerTrust] attemptServerTrustAuthentication retval ${retval}, reset to 0x1`); | ||
let fakeret = new NativePointer(0x1) | ||
retval.replace(fakeret) | ||
} | ||
} | ||
}); | ||
|
||
} catch (e) { | ||
log(`[HookAFServerTrust] fail to hook attemptServerTrustAuthentication !, ${e}`); | ||
} | ||
} | ||
|
||
export { | ||
attach, | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { log } from "./logger"; | ||
import { SDSwiftDataStorage } from "./SDSwiftDataStorage"; | ||
import * as SDNetDump from "./SDNetDump"; | ||
import * as SwiftRuntime from "./SwiftRuntime"; | ||
|
||
function enterFuncUrlSessionDidReceive(this: InvocationContext, args: InvocationArguments) { | ||
// String is parsed by value | ||
let ptr1 = args[0]; //NSURLSession | ||
let ptr2 = args[1]; //NSURLSessionDataTask | ||
let rangePtr = args[2]; | ||
let dataStoragePtr = args[3]; // Foundation.__DataStorage <-> Swift.Data | ||
|
||
|
||
const session = new ObjC.Object(ptr1); //NSURLSession | ||
const sessionDataTask = new ObjC.Object(ptr2); //NSURLSessionDataTask | ||
|
||
const request = sessionDataTask.currentRequest(); //NSURLRequest | ||
const dataLen = sessionDataTask.response().expectedContentLength() | ||
//log(`1112-> ${request} > ${request.URL().absoluteString()}`) | ||
|
||
let output:string = SDNetDump.dumpRequest(request); | ||
|
||
|
||
//log(`rangePtr = ${ rangePtr }, dataStoragePtr=${dataStoragePtr}`); | ||
//log(`dataLen=${dataLen}`); | ||
|
||
let sdata = new SDSwiftDataStorage(dataStoragePtr); | ||
//log(` ${ sdata.bytesPtr.readCString() }`); | ||
|
||
let sdataStr = sdata.bytesPtr.readCString(dataLen); // parse the response data, default as string | ||
|
||
output += "\n"; | ||
output += SDNetDump.intent + `>>> ${sdataStr}`; | ||
log(`${output}`) | ||
|
||
//---- | ||
// you can also use the following function to print Data. | ||
//SwiftRuntime.swiftDataBridgeToObjectiveCByPtr(rangePtr, dataStoragePtr); | ||
|
||
} | ||
|
||
function attach() { | ||
try { | ||
//Alamofire.SessionDelegate.urlSession(_: __C.NSURLSession, dataTask: __C.NSURLSessionDataTask, didReceive: Foundation.Data) -> () | ||
const func_urlSessionDidReceive = Module.getExportByName(null, '$s9Alamofire15SessionDelegateC03urlB0_8dataTask10didReceiveySo12NSURLSessionC_So0i4DataF0C10Foundation0J0VtF'); | ||
log(`[HookAFSessionDelegate] func_urlSession ${func_urlSessionDidReceive}`); | ||
Interceptor.attach(func_urlSessionDidReceive, { onEnter: enterFuncUrlSessionDidReceive}); | ||
} catch (e) { | ||
log(`[HookAFSessionDelegate] fail to hook Alamofire.SessionDelegate !, ${e}`); | ||
} | ||
|
||
} | ||
|
||
export { | ||
attach, | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { log } from "./logger"; | ||
import * as Util from "./Util"; | ||
import * as SDNetDump from "./SDNetDump"; | ||
|
||
|
||
|
||
function enterFuncDataTaskWithRequest(this: InvocationContext, args: InvocationArguments) { | ||
//const ptr = args[0]; | ||
const ptr2 = args[2]; | ||
const rqst = new ObjC.Object(ptr2); // rqst=NSMutableURLRequest | ||
let rqstDesc = SDNetDump.dumpRequest(rqst); | ||
// https://github.com/theart42/hack.lu/blob/master/IOS/Notes/02-HTTPS/00-https-hooks.md | ||
|
||
let ptr3 = args[3]; | ||
if (ptr3.toInt32() <= 0) { | ||
var str:string = rqstDesc; | ||
str += "\n"; | ||
str += SDNetDump.intent + "(completionHandler empty)"; | ||
log(`${str}`) | ||
return; | ||
} | ||
|
||
var completionHandler = new ObjC.Block(args[3]); | ||
var origCompletionHandlerBlock = completionHandler.implementation; | ||
|
||
completionHandler.implementation = function(data, response, error){ | ||
var str:string = rqstDesc; | ||
str += "\n"; | ||
str += SDNetDump.dumpRspWith(data, response, error); | ||
log(`${rqstDesc}`); | ||
return origCompletionHandlerBlock(data, response, error); | ||
} | ||
} | ||
|
||
|
||
function attach() { | ||
const hookDataTask = Util.getOCMethodName('NSURLSession', '- dataTaskWithRequest:completionHandler:'); | ||
log(`hook NSURLSession ${hookDataTask.implementation}`); | ||
|
||
Interceptor.attach(hookDataTask.implementation, { | ||
onEnter : enterFuncDataTaskWithRequest, | ||
}); | ||
|
||
} | ||
|
||
|
||
|
||
export { | ||
attach, | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { log } from "./logger"; | ||
import * as Util from "./Util"; | ||
import {SDSwiftLargeString, SDSwiftSmallString} from "./SDSwiftString"; | ||
|
||
function isSmallString(abcdeeee: UInt64):boolean { | ||
let abcd = abcdeeee.shr(4).and(0xF); | ||
let isSmall = abcd.and(0x2).valueOf() > 0; | ||
return isSmall; | ||
} | ||
|
||
function enterFuncDataTaskWithRequest(this: InvocationContext, args: InvocationArguments) { | ||
// String is parsed by value | ||
let ptr1 = args[0]; | ||
let ptr2 = args[1]; | ||
|
||
//log(`ptr ${ptr1}, ${ptr1.toString()}, ${ptr2.toString()} `); | ||
|
||
let ptr1hex = '0x' + ptr1.toString(16); | ||
let ptr2hex = '0x' + ptr2.toString(16); | ||
|
||
let ptr1value = new UInt64(ptr1hex); | ||
let ptr2value = new UInt64(ptr2hex); | ||
let smallObject = ptr2value.and(0xFF); // the last byte | ||
|
||
// first, try parse smallstring | ||
if (isSmallString(smallObject)) { | ||
let smallStr = new SDSwiftSmallString(ptr1hex, ptr2hex); | ||
log(`[Foundation.URL.init] a=${smallStr.desc()}`) | ||
if (Util.isPrintableString(smallStr.strValue)) { //TODO: filter special char | ||
log(`[Foundation.URL.init] ${smallStr.desc()}`) | ||
return; | ||
} | ||
|
||
} | ||
|
||
// Large String | ||
const countAndFlagsBitsPtr = args[0]; // 8 bytes(_countAndFlagsBits) | ||
const objectPtr = args[1]; // 8 bytes(_object) | ||
|
||
let countAndFlagsBits = new UInt64('0x' + countAndFlagsBitsPtr.toString(16)) | ||
let object = new UInt64('0x' + objectPtr.toString(16)); | ||
//log(`[Foundation.URL.init] arg ptr=${countAndFlagsBitsPtr} ,${objectPtr} -> ${objectPtr.toString(16)}`); | ||
//log(`countAndFlagsBits=0x${countAndFlagsBits.toString(16) } , object=0x${object.toString(16) }`); | ||
|
||
let largeStr = new SDSwiftLargeString(countAndFlagsBits, object); | ||
log(`[Foundation.URL.init] ${largeStr.desc()}`) | ||
} | ||
|
||
|
||
function attach() { | ||
try { | ||
// s10Foundation3URLV6stringACSgSSh_tcfC ---> Foundation.URL.init(string: __shared Swift.String) -> Foundation.URL? | ||
let func_Foundation_URL_init = Module.getExportByName(null, '$s10Foundation3URLV6stringACSgSSh_tcfC'); // remove prefix _ | ||
console.log('func_Foundation_URL_init', func_Foundation_URL_init) | ||
Interceptor.attach(func_Foundation_URL_init, { onEnter: enterFuncDataTaskWithRequest }); | ||
} catch (e) { | ||
log(`[HookURL] fail to hook swift Foundation.URL.init !, ${e}`); | ||
} | ||
} | ||
|
||
export { | ||
attach, | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import {colorfulStr, LogColor} from "./logger" | ||
|
||
export const intent:string = " "; | ||
export const newline:string = "\n"; | ||
|
||
function dumpRequest(rqst:ObjC.Object):string { | ||
// rqst=NSMutableURLRequest | ||
// https://developer.apple.com/documentation/foundation/nsmutableurlrequest?language=objc | ||
let urlstr = rqst.URL().absoluteString(); | ||
let method = rqst.HTTPMethod().toString(); // NSString | ||
let bodyData = rqst.HTTPBody(); | ||
let allHTTPHeaderFields = rqst.allHTTPHeaderFields().toString() as string; | ||
|
||
var str:string = ""; | ||
let redMethod = colorfulStr(`[${method}]`, LogColor.Red); | ||
str += `${redMethod} ${urlstr}`; | ||
if (allHTTPHeaderFields && allHTTPHeaderFields.length > 0) { | ||
str += newline; | ||
str += intent + `[Header] ${allHTTPHeaderFields.replace(newline, "")}`; | ||
} | ||
// NSData to NSString | ||
if (bodyData) { | ||
var bodydataStr = ObjC.classes.NSString.alloc().initWithData_encoding_(bodyData, 4); | ||
str += newline; | ||
str += intent + "[Body] " + bodydataStr; | ||
} | ||
return str; | ||
} | ||
|
||
function dumpRspWith(data:any, response:any, error:any):string { | ||
let rsp = new ObjC.Object(response); | ||
var dataNSString = ObjC.classes.NSString.alloc().initWithData_encoding_(data, 4); | ||
|
||
let str = intent + `>>> ${dataNSString}`; | ||
return str; | ||
} | ||
|
||
export { | ||
dumpRequest, | ||
dumpRspWith, | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
|
||
export class SDSwiftDataStorage { | ||
// https://github.com/apple/swift-corelibs-foundation/blob/60fb6984c95b989bb25b3af26accd3a2dc2e2240/Sources/Foundation/Data.swift#L82 | ||
// Swift DataStorage is a class type. | ||
// Foundation.__DataStorage | ||
// https://github.com/TannerJin/Swift-MemoryLayout/blob/master/Swift/Class.swift | ||
__dataStoragePtr: NativePointer; | ||
bytesPtr: NativePointer | ||
length: UInt64 | ||
capacity: UInt64 | ||
|
||
constructor(ptr: NativePointer) { | ||
/* | ||
----Swift Class Memory Layout---- | ||
var isa: objc_class* (8 bytes) | ||
var refCount: UInt64 (8 bytes) | ||
[properties] | ||
*/ | ||
this.__dataStoragePtr = ptr; | ||
|
||
let tmpptr = ptr.add(8 + 8); | ||
this.bytesPtr = new NativePointer( tmpptr.readU64() ); | ||
|
||
tmpptr = tmpptr.add(8); | ||
this.length = tmpptr.readU64(); | ||
|
||
tmpptr = tmpptr.add(8); | ||
this.capacity = tmpptr.readU64(); | ||
} | ||
|
||
desc():string { | ||
return `<Swift.DataStorage, bytesPtr=${this.bytesPtr}, length='${this.length}'>`; | ||
} | ||
} |
Oops, something went wrong.