-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
first support of Flutter - still not integrated for a plattform
- Loading branch information
1 parent
b3c1736
commit 8db416b
Showing
5 changed files
with
230 additions
and
6 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
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,101 @@ | ||
|
||
import { Flutter } from "../ssl_lib/flutter.js"; | ||
import { socket_library } from "./android_agent.js"; | ||
import {PatternBasedHooking } from "../shared/pattern_based_hooking.js"; | ||
import { patterns, isPatternReplaced } from "../ssl_log.js" | ||
import { devlog } from "../util/log.js"; | ||
|
||
|
||
export class Flutter_Android extends Flutter { | ||
private default_pattern: { [arch: string]: { primary: string; fallback: string } }; | ||
|
||
constructor(public moduleName:string, public socket_library:String, is_base_hook: boolean){ | ||
super(moduleName,socket_library,is_base_hook); | ||
|
||
this.default_pattern = { | ||
"x64": { | ||
primary: "55 41 57 41 56 41 55 41 54 53 48 83 EC 48 48 8B 47 68 48 83 B8 20 02 00 00 00 0F 84 FE 00 00 00", // Primary pattern | ||
fallback: "55 41 57 41 56 41 55 41 54 53 48 83 EC 48 48 8B 47 68 48 83 B8 20 02 00 00 00" // Fallback pattern | ||
}, | ||
"x86": { | ||
primary: "55 53 57 56 83 EC 4C E8 00 00 00 00 5B 81 C3 A9 CB 13 00 8B 44 24 60 8B 40 34", // Primary pattern | ||
fallback: "55 53 57 56 83 EC 4C E8 00 00 00 00 5B 81 C3 A9 CB 13 00 8B 44 24 60" // Fallback pattern | ||
}, | ||
"arm64": { | ||
primary: "3F 23 03 D5 FF C3 01 D1 FD 7B 04 A9 F6 57 05 A9 F4 4F 06 A9 FD 03 01 91 08 34 40 F9 08 11 41 F9 C8 07 00 B4", // Primary pattern | ||
fallback: "3F 23 03 D5 FF 03 02 D1 FD 7B 04 A9 F7 2B 00 F9 F6 57 06 A9 F4 4F 07 A9 FD 03 01 91 08 34 40 F9 08 11 41 F9 E8 0F 00 B4" // Fallback pattern | ||
}, | ||
"arm": { | ||
primary: "2D E9 F0 43 89 B0 04 46 40 6B D0 F8 2C 01 00 28 49 D0", // Primary pattern | ||
fallback: "2D E9 F0 43 89 B0 04 46 40 6B D0 F8 2C 01 00 28 49 D0" // Fallback pattern (right now we don't have any) | ||
} | ||
}; | ||
} | ||
|
||
|
||
|
||
// Simulated JSON object (you can replace this with actual file loading) | ||
|
||
|
||
private get_CPU_specific_pattern(): { primary: string; fallback: string } { | ||
let arch = Process.arch.toString(); // Get architecture, e.g., "x64", "arm64" | ||
if(arch == "ia32"){ | ||
arch = "x86" | ||
} | ||
|
||
if (this.default_pattern[arch]) { | ||
return this.default_pattern[arch]; // Return the pattern for the architecture | ||
} else { | ||
throw new Error(`No patterns found for CPU architecture: ${arch}`); | ||
} | ||
} | ||
|
||
install_key_extraction_hook(){ | ||
const flutterModule = Process.findModuleByName(this.module_name); | ||
const hooker = new PatternBasedHooking(flutterModule); | ||
|
||
if (isPatternReplaced()){ | ||
devlog("Hooking libflutter functions by patterns from JSON file"); | ||
hooker.hook_DumpKeys(this.module_name,"libflutter.so",patterns,(args: any[]) => { | ||
this.dumpKeys(args[1], args[0], args[2]); // Unpack args into dumpKeys | ||
}); | ||
}else{ | ||
// This are the default patterns for hooking ssl_log_secret in BoringSSL inside Flutter | ||
hooker.hookModuleByPattern( | ||
this.get_CPU_specific_pattern(), | ||
(args) => { | ||
this.dumpKeys(args[1], args[0], args[2]); // Hook args passed to dumpKeys | ||
} | ||
); | ||
} | ||
|
||
} | ||
|
||
execute_hooks(){ | ||
this.install_key_extraction_hook(); | ||
} | ||
|
||
} | ||
|
||
|
||
export function flutter_execute(moduleName:string, is_base_hook: boolean){ | ||
var flutter = new Flutter_Android(moduleName,socket_library,is_base_hook); | ||
try { | ||
flutter.execute_hooks(); | ||
}catch(error_msg){ | ||
devlog(`flutter_execute error: ${error_msg}`) | ||
} | ||
|
||
if (is_base_hook) { | ||
try { | ||
const init_addresses = flutter.addresses[moduleName]; | ||
// ensure that we only add it to global when we are not | ||
if (Object.keys(init_addresses).length > 0) { | ||
(global as any).init_addresses[moduleName] = init_addresses; | ||
} | ||
}catch(error_msg){ | ||
devlog(`flutter_execute base-hook error: ${error_msg}`) | ||
} | ||
} | ||
|
||
} |
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,125 @@ | ||
import { get_hex_string_from_byte_array, readAddresses } from "../shared/shared_functions.js"; | ||
import { devlog } from "../util/log.js"; | ||
|
||
|
||
|
||
|
||
export class Flutter { | ||
|
||
|
||
// global variables | ||
library_method_mapping: { [key: string]: Array<string> } = {}; | ||
addresses: { [libraryName: string]: { [functionName: string]: NativePointer } }; | ||
module_name: string; | ||
is_base_hook: boolean; | ||
|
||
|
||
constructor(public moduleName:string, public socket_library:String,is_base_hook: boolean ,public passed_library_method_mapping?: { [key: string]: Array<string> } ){ | ||
this.module_name = moduleName; | ||
this.is_base_hook = is_base_hook; | ||
|
||
if(typeof passed_library_method_mapping !== 'undefined'){ | ||
this.library_method_mapping = passed_library_method_mapping; | ||
}else{ | ||
this.library_method_mapping[`*${socket_library}*`] = ["getpeername", "getsockname", "ntohs", "ntohl"] | ||
} | ||
|
||
this.addresses = readAddresses(moduleName,this.library_method_mapping); | ||
} | ||
|
||
get_client_random(s3_ptr: NativePointer, SSL3_RANDOM_SIZE: number): string { | ||
if (!s3_ptr.isNull()) { | ||
const client_random_ptr: NativePointer = s3_ptr.add(0x30); // Offset in s3 struct | ||
//@ts-ignore | ||
const client_random = Memory.readByteArray(client_random_ptr, SSL3_RANDOM_SIZE); | ||
|
||
// Convert the byte array to a hex string | ||
const hexClientRandom = get_hex_string_from_byte_array(new Uint8Array(client_random as ArrayBuffer)); | ||
|
||
return hexClientRandom; | ||
} else { | ||
devlog("[Error] s3 pointer is NULL"); | ||
return ""; | ||
} | ||
} | ||
|
||
get_client_random_from_ssl_struct(ssl_st_ptr: NativePointer): string { | ||
const SSL3_RANDOM_SIZE = 32; | ||
let offset_s3: number; | ||
|
||
switch (Process.arch) { | ||
case 'x64': | ||
offset_s3 = 0x30; | ||
break; | ||
case 'arm64': | ||
offset_s3 = 0x30; | ||
break; | ||
case 'ia32': | ||
offset_s3 = 0x2C; | ||
break; | ||
case 'arm': | ||
offset_s3 = 0x2C; | ||
break; | ||
default: | ||
devlog("[Error] Unsupported architecture"); | ||
return ""; | ||
} | ||
|
||
const s3_ptr = ssl_st_ptr.add(offset_s3).readPointer(); | ||
return this.get_client_random(s3_ptr, SSL3_RANDOM_SIZE); | ||
} | ||
|
||
|
||
dumpKeys(labelPtr: NativePointer, sslStructPtr: NativePointer, keyPtr: NativePointer): void { | ||
const KEY_LENGTH = 32; // Assuming key length is 32 bytes | ||
|
||
let labelStr = ''; | ||
let client_random = ''; | ||
let secret_key = ''; | ||
|
||
// Read the label (the label pointer might contain a C string) | ||
if (!labelPtr.isNull()) { | ||
labelStr = labelPtr.readCString() ?? ''; // Read label as a C string | ||
//devlog(`Label: ${labelStr}`); | ||
} else { | ||
devlog("[Error] Argument 'labelPtr' is NULL"); | ||
} | ||
|
||
// Extract client_random from the SSL structure | ||
if (!sslStructPtr.isNull()) { | ||
client_random = this.get_client_random_from_ssl_struct(sslStructPtr) | ||
}else { | ||
devlog("[Error] Argument 'sslStructPtr' is NULL"); | ||
} | ||
|
||
if (!keyPtr.isNull()) { | ||
//@ts-ignore | ||
const keyData = Memory.readByteArray(keyPtr, KEY_LENGTH); // Read the key data (KEY_LENGTH bytes) | ||
|
||
// Convert the byte array to a string of hex values | ||
const hexKey = get_hex_string_from_byte_array(keyData); | ||
|
||
secret_key = hexKey; | ||
} else { | ||
devlog("[Error] Argument 'key' is NULL"); | ||
} | ||
|
||
//devlog("invoking ssl_log_secret() from BoringSSL statically linked into Cronet"); | ||
var message: { [key: string]: string | number | null } = {} | ||
message["contentType"] = "keylog" | ||
message["keylog"] = labelStr+" "+client_random+" "+secret_key; | ||
send(message) | ||
} | ||
|
||
install_plaintext_read_hook(){ | ||
// TBD | ||
} | ||
|
||
install_plaintext_write_hook(){ | ||
// TBD | ||
} | ||
|
||
install_key_extraction_hook(){ | ||
// needs to be setup for the specific plattform | ||
} | ||
} |
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
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