-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding frida FaceTime implementation
- Loading branch information
Natalie Silvanovich
committed
Oct 15, 2019
1 parent
d5703be
commit c74c937
Showing
5 changed files
with
394 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,29 @@ | ||
FaceTime Replay for Frida! | ||
|
||
This implementation has some limitations compared to the native implementation, specifically it is slow enough to alter the behavior of the audio and video streams. That said, it is much faster to set up than the native version. | ||
|
||
Set-up instructions: | ||
|
||
1) Add the line: | ||
|
||
(subpath "/out") | ||
|
||
to the (allow file-read* file-write* section of /System/Library/Sandbox/Profiles/com.apple.avconferenced.sb, and restart the host | ||
|
||
2) Create the directory /out and make it world-readable | ||
|
||
3) Install frida, and run the following in the local directory | ||
|
||
python3 dumpIncomingMessages.py | ||
|
||
Note that this runs on an MacBook Air on version 10.14.6. For a different version, the offsets of the hooked methods in the JS files need to be recalculated. | ||
|
||
4) Use FaceTime to call the target and answer the call. This call will be recorded in /out | ||
|
||
To reproduce the call: | ||
|
||
1) Run: | ||
|
||
python3 replay.py | ||
|
||
2) Use FaceTime to call the target and answer the call. |
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,49 @@ | ||
# Copyright 2018 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
import frida | ||
import sys | ||
import os | ||
|
||
vid_index=0 | ||
aud_index = 0 | ||
|
||
def on_message(message, data): | ||
global vid_index | ||
global aud_index | ||
print(message) | ||
if 'payload' in message: | ||
payload = message['payload'] | ||
print(payload) | ||
f = open(payload, 'rb') | ||
s = f.read() | ||
f.close() | ||
pt = s[1]&0x7f; | ||
|
||
if pt == 0x7b: | ||
f = open("/out/vid" + str(vid_index), 'wb') | ||
f.write(s) | ||
f.close() | ||
vid_index = vid_index + 1 | ||
if pt == 0x68: | ||
f = open("/out/aud" + str(aud_index), 'wb') | ||
f.write(s) | ||
f.close() | ||
aud_index = aud_index + 1 | ||
os.remove(payload) | ||
|
||
|
||
|
||
session = frida.attach("avconferenced") | ||
code = open('dumpMessages.js', 'r').read() | ||
script = session.create_script(code); | ||
script.on("message", on_message) | ||
script.load() | ||
|
||
print("Press Ctrl-C to quit") | ||
sys.stdin.read() |
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,80 @@ | ||
// Copyright 2018 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
var ind = 0; | ||
var unpaired =[] | ||
var paired = [] | ||
|
||
send("Hooking VTP_Send"); | ||
Interceptor.attach(Module.getExportByName(null, "hwrandom").add(0x10085c), { | ||
onEnter: function(args) { | ||
console.log("pack len " + args[2]) | ||
var p1 = args[1].readByteArray(args[2].toInt32()); | ||
var p = new Uint8Array(p1); | ||
var ext = p[0]&0x10; | ||
var len = 0 | ||
var pt = p[1]&0x7f; | ||
console.log(p[1]) | ||
console.log(pt) | ||
if(pt == 0x7b || pt == 0x68){ | ||
|
||
if(ext){ | ||
len = p[15]*4+4 +12; | ||
|
||
}else{ | ||
len = 12; | ||
} | ||
var this_pair=0; | ||
for(var key in paired){ | ||
var e = new Uint8Array(paired[key][1]); | ||
if(e.length == p.length - len){ | ||
match = true; | ||
for(var i = 0; i < e.length; i++){ | ||
if(e[i] != p[i+len]){ | ||
match = false | ||
} | ||
if(match){ | ||
this_pair = paired[key]; | ||
} | ||
} | ||
} | ||
} | ||
if(!this_pair){ | ||
send("PAIR ERROR"); | ||
} | ||
|
||
var s = "/out/test" + ind; | ||
ind = ind + 1; | ||
var f = new File(s, "wb") | ||
f.write(Array.prototype.slice.call(p, 0, len)); | ||
console.log("pair length " + this_pair[0].byteLength) | ||
f.write(this_pair[0]) | ||
f.close() | ||
send(s); | ||
} | ||
} | ||
}); | ||
|
||
Interceptor.attach(Module.getExportByName(null, "CCCryptorUpdate"), { | ||
onEnter: function(args) { | ||
|
||
var p = args[1].readByteArray(args[2].toInt32()); | ||
|
||
this.unencrypted = p; | ||
this.ptr = args[1]; | ||
this.len = args[2].toInt32(); | ||
|
||
}, | ||
onLeave: function(retval) { | ||
|
||
var p = this.ptr.readByteArray(this.len); | ||
|
||
paired.push([this.unencrypted, p]) | ||
|
||
} | ||
}); |
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,205 @@ | ||
// Copyright 2018 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
var ind = 0; | ||
var unpaired =[] | ||
var paired = [] | ||
var aud_thread=0 | ||
var vid_thread=0 | ||
var audind = 0; | ||
var vidind=0; | ||
var audq = []; | ||
var vidq = [] | ||
var first_aud_seq = 0; | ||
var first_aud_seqr = 0; | ||
var first_vid_seq = 0; | ||
var first_vid_seqr = 0; | ||
var save = []; | ||
send("Hooking VTP_Send"); | ||
|
||
Interceptor.attach(Module.getExportByName(null, "hwrandom").add(0xdd820), { | ||
onEnter: function(args) { | ||
var old = aud_thread; | ||
if(aud_thread && old != aud_thread){ | ||
|
||
console.log("error aud"); | ||
} | ||
|
||
aud_thread = Process.getCurrentThreadId(); | ||
|
||
|
||
} | ||
}); | ||
|
||
Interceptor.attach(Module.getExportByName(null, "hwrandom").add(0x229c9), { | ||
onEnter: function(args) { | ||
var old = vid_thread; | ||
if(vid_thread && old != vid_thread){ | ||
|
||
console.log("error vid"); | ||
} | ||
|
||
vid_thread = Process.getCurrentThreadId(); | ||
|
||
} | ||
}); | ||
|
||
Interceptor.attach(Module.getExportByName(null, "hwrandom").add(0x10085c), { | ||
onEnter: function(args) { | ||
|
||
var p1 = args[1].readByteArray(args[2].toInt32()); | ||
var p = new Uint8Array(p1, 0, args[2].toInt32()); | ||
var ext = p[0]&0x10; | ||
var len = 0 | ||
var pt = p[1]&0x7f; | ||
|
||
if(pt == 0x7b || pt == 0x68){ | ||
|
||
pack = 0 | ||
var is_vid = 0; | ||
if(pt==0x7b){ | ||
is_vid=1; | ||
pack = vidq[0]; | ||
vidq.shift() | ||
if(first_vid_seq==0){ | ||
first_vid_seq = p[2] + (p[3] << 8); | ||
var data = pack[0]; | ||
var q = new Uint8Array(pack[0].readByteArray(20), 0, 20); | ||
first_vid_seqr = q[2] + (q[3] << 8); | ||
} | ||
}else if(pt == 0x68){ | ||
pack = audq[0]; | ||
audq.shift() | ||
if(first_aud_seq==0){ | ||
first_aud_seq = p[2] + (p[3] << 8); | ||
var data = pack[0]; | ||
var q = new Uint8Array(pack[0].readByteArray(20), 0, 20); | ||
first_aud_seqr = q[2] + (q[3] << 8); | ||
} | ||
}else{ | ||
console.log("NO PACKET"); | ||
return; | ||
} | ||
|
||
|
||
var tdata = pack[0]; | ||
var data = Memory.alloc(2048); | ||
Memory.copy(data, tdata, pack[1]); | ||
|
||
var q = new Uint8Array(pack[0].readByteArray(20), 0, 20); | ||
if(is_vid){ | ||
var curr_seq = q[2] + (q[3] << 8); | ||
var seq = first_vid_seq + (curr_seq- first_vid_seqr); | ||
console.log("seq "+seq + " q " + q.byteLength); | ||
data.add(2).writeByteArray([seq&0xff, (seq&0xff00) >> 8]); | ||
|
||
}else{ | ||
var curr_seq = q[2] + (q[3] << 8); | ||
var seq = first_aud_seq + (curr_seq- first_aud_seqr); | ||
console.log("seq "+seq + " q " + q.byteLength); | ||
data.add(2).writeByteArray([seq&0xff, (seq&0xff00) >> 8]); | ||
|
||
} | ||
|
||
data.add(4).writeByteArray([q[4], q[5], q[6], q[7], p[8], p[9], p[10], p[11]]); | ||
args[1] = data; | ||
args[2] = new NativePointer(pack[1]); | ||
|
||
|
||
var s = 0 | ||
if(is_vid){ | ||
s = "/out/vidtest" + vidind; | ||
}else{ | ||
|
||
s = "/out/audtest" + audind; | ||
} | ||
var f = new File(s, "wb") | ||
|
||
f.write(data.readByteArray(pack[1])); | ||
f.close() | ||
save.push(data); | ||
console.log("sent" + args[2]); | ||
|
||
} | ||
} | ||
}); | ||
|
||
var ccc = Interceptor.attach(Module.getExportByName(null, "CCCryptorUpdate"), { | ||
onEnter: function(args) { | ||
if(Process.getCurrentThreadId()==aud_thread){ | ||
console.log("START AUD " + audind); | ||
var d = ObjC.classes.NSData.dataWithContentsOfFile_("/out/aud" + audind); | ||
audind++; | ||
var realbytes = ptr(d.bytes()); | ||
var tmp = realbytes.readByteArray(d.length()); | ||
var m = Memory.alloc(d.length()); | ||
|
||
|
||
Memory.copy(m, realbytes, d.length()); | ||
var p = new Uint8Array(tmp); | ||
var ext = p[0]&0x10; | ||
var len = 0; | ||
if(ext){ | ||
len = p[15]*4+4 +12; | ||
|
||
}else{ | ||
len = 12; | ||
} | ||
|
||
|
||
|
||
console.log("/out/aud" + audind + " u "+ d); | ||
console.log(m); | ||
console.log(m.add(len)); | ||
console.log(d.length()-len); | ||
args[1] = m.add(len); | ||
args[2] = new NativePointer(d.length()-len); | ||
args[3] = m.add(len); | ||
args[4] = new NativePointer(d.length()-len); | ||
console.log(m); | ||
|
||
audq.push([m, d.length(), d]); | ||
|
||
console.log("aud end"); | ||
} | ||
|
||
if(Process.getCurrentThreadId()==vid_thread){ | ||
console.log("START VID" + vidind); | ||
var d = ObjC.classes.NSData.dataWithContentsOfFile_("/out/vid" + vidind); | ||
|
||
vidind++; | ||
var realbytes = ptr(d.bytes()); | ||
var tmp = realbytes.readByteArray(d.length()); | ||
var m = Memory.alloc(d.length()); | ||
Memory.copy(m, realbytes, d.length()); | ||
var p = new Uint8Array(tmp); | ||
var ext = p[0]&0x10; | ||
var len = 0; | ||
if(ext){ | ||
len = p[15]*4+4 +12; | ||
|
||
}else{ | ||
len = 12; | ||
} | ||
|
||
console.log(d); | ||
console.log(m.add(len)); | ||
console.log(d.length()-len); | ||
|
||
console.log(m); | ||
args[1] = m.add(len); | ||
args[2] = new NativePointer(d.length()-len); | ||
args[3] = m.add(len); | ||
args[4] = new NativePointer(d.length()-len); | ||
|
||
|
||
vidq.push([m, d.length(), d]); | ||
console.log("vid end"); | ||
} | ||
} | ||
}); |
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,31 @@ | ||
# Copyright 2018 Google LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
import frida | ||
import sys | ||
import os | ||
|
||
vid_index=0 | ||
aud_index = 0 | ||
|
||
def on_message(message, data): | ||
global vid_index | ||
global aud_index | ||
print(message) | ||
|
||
|
||
|
||
|
||
session = frida.attach("avconferenced") | ||
code = open('replay.js', 'r').read() | ||
script = session.create_script(code); | ||
script.on("message", on_message) | ||
script.load() | ||
|
||
print("Press Ctrl-C to quit") | ||
sys.stdin.read() |