Skip to content

Commit

Permalink
✨ Allow declaring function identifiers in config files
Browse files Browse the repository at this point in the history
See also: #16
  • Loading branch information
ShellWen committed Nov 28, 2023
1 parent fd2af2d commit eb6802a
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 63 deletions.
19 changes: 11 additions & 8 deletions crates/core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,28 @@ use std::path::Path;

use serde::Deserialize;

use crate::matcher::SourceMatcher;
use crate::identifier::Identifiers;
use crate::matcher::SourceMatcherEnum;
use crate::processor::SourceProcessor;

#[derive(Deserialize, Debug)]
pub struct ConfigRule {
pub matcher: Box<SourceMatcher>,
pub processors: Vec<SourceProcessor>,
pub(crate) struct ConfigRule {
pub(crate) matcher: Box<SourceMatcherEnum>,
pub(crate) processors: Vec<SourceProcessor>,
}

#[derive(Deserialize, Debug)]
pub struct Config {
pub rules: HashMap<String, ConfigRule>,
pub(crate) struct Config {
#[serde(default)]
pub(crate) identifiers: Identifiers,
pub(crate) rules: HashMap<String, ConfigRule>,
}

pub trait FileConfig {
pub(crate) trait ReadFromFile {
fn load_from_toml(file_path: &Path) -> Config;
}

impl FileConfig for Config {
impl ReadFromFile for Config {
fn load_from_toml(file_path: &Path) -> Config {
let mut file = File::open(file_path).expect("open config file failed");
let mut file_content = String::new();
Expand Down
1 change: 1 addition & 0 deletions crates/core/src/core.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::ops::Deref;

use crate::config::Config;
use crate::matcher::SourceMatcher;
use crate::source::Source;
use crate::v8_sys::{
local_string_from_string, string_from_local_string, v8_context_get_isolate, V8Context, V8Source,
Expand Down
128 changes: 128 additions & 0 deletions crates/core/src/identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use frida_gum::{Module, NativePointer};
use serde::Deserialize;

#[allow(non_snake_case)]
#[derive(Deserialize, Debug)]
pub(crate) struct Identifiers {
pub(crate) V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL: Vec<IdentifierEnum>,
pub(crate) V8_STRING_UTF8LENGTH: Vec<IdentifierEnum>,
pub(crate) V8_STRING_WRITE_UTF8: Vec<IdentifierEnum>,
pub(crate) V8_CONTEXT_GET_ISOLATE: Vec<IdentifierEnum>,
pub(crate) V8_STRING_NEW_FROM_UTF8: Vec<IdentifierEnum>,
}

pub(crate) trait Identifier {
fn identify(&self) -> Option<NativePointer>;
}

impl Identifier for Vec<IdentifierEnum> {
fn identify(&self) -> Option<NativePointer> {
for identifier in self {
let ptr = identifier.identify();
if ptr.is_some() {
return ptr;
}
}
None
}
}

#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
pub(crate) enum IdentifierEnum {
#[serde(rename = "symbol")]
SymbolIdentifier(SymbolIdentifier),
#[serde(rename = "rva")]
RvaIdentifier(RvaIdentifier),
}

impl Identifier for IdentifierEnum {
fn identify(&self) -> Option<NativePointer> {
match self {
IdentifierEnum::SymbolIdentifier(identifier) => identifier.identify(),
IdentifierEnum::RvaIdentifier(identifier) => identifier.identify(),
}
}
}

#[derive(Deserialize, Debug)]
pub(crate) struct SymbolIdentifier {
pub(crate) symbols: Vec<String>,
}

impl Identifier for SymbolIdentifier {
fn identify(&self) -> Option<NativePointer> {
for symbol in &self.symbols {
let ptr = Module::find_export_by_name(None, symbol);
if ptr.is_some() {
return ptr;
}
}
None
}
}

#[derive(Deserialize, Debug)]
pub(crate) struct RvaIdentifier {
pub(crate) module_name: String,
pub(crate) rva: usize,
}

impl Identifier for RvaIdentifier {
fn identify(&self) -> Option<NativePointer> {
let base_address = Module::find_base_address(&self.module_name);
if base_address.is_null() {
return None;
}
Some(NativePointer(unsafe { base_address.0.add(self.rva) }))
}
}

impl Default for Identifiers {
fn default() -> Self {
Identifiers {
V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL: vec![
IdentifierEnum::SymbolIdentifier(SymbolIdentifier {
symbols: vec![
"_ZN2v814ScriptCompiler23CompileFunctionInternalENS_5LocalINS_7ContextEEEPNS0_6SourceEmPNS1_INS_6StringEEEmPNS1_INS_6ObjectEEENS0_14CompileOptionsENS0_13NoCacheReasonEPNS1_INS_14ScriptOrModuleEEE"
.to_string(),
"?CompileFunctionInternal@ScriptCompiler@v8@@CA?AV?$MaybeLocal@VFunction@v8@@@2@V?$Local@VContext@v8@@@2@PEAVSource@12@_KQEAV?$Local@VString@v8@@@2@2QEAV?$Local@VObject@v8@@@2@W4CompileOptions@12@W4NoCacheReason@12@PEAV?$Local@VScriptOrModule@v8@@@2@@Z"
.to_string(),
],
})
],
V8_STRING_UTF8LENGTH: vec![
IdentifierEnum::SymbolIdentifier(SymbolIdentifier {
symbols: vec![
"_ZNK2v86String10Utf8LengthEPNS_7IsolateE".to_string(),
"?Utf8Length@String@v8@@QEBAHPEAVIsolate@2@@Z".to_string(),
],
}
)],
V8_STRING_WRITE_UTF8: vec![
IdentifierEnum::SymbolIdentifier(SymbolIdentifier {
symbols: vec![
"_ZNK2v86String9WriteUtf8EPNS_7IsolateEPciPii".to_string(),
"?WriteUtf8@String@v8@@QEBAHPEAVIsolate@2@PEADHPEAHH@Z".to_string(),
],
}
)],
V8_CONTEXT_GET_ISOLATE: vec![
IdentifierEnum::SymbolIdentifier(SymbolIdentifier {
symbols: vec![
"_ZN2v87Context10GetIsolateEv".to_string(),
"?GetIsolate@Context@v8@@QEAAPEAVIsolate@2@XZ".to_string(),
],
}
)],
V8_STRING_NEW_FROM_UTF8: vec![
IdentifierEnum::SymbolIdentifier(SymbolIdentifier {
symbols: vec![
"_ZN2v86String11NewFromUtf8EPNS_7IsolateEPKcNS_13NewStringTypeEi".to_string(),
"?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PEAVIsolate@2@PEBDW4NewStringType@2@H@Z".to_string(),
],
}
)],
}
}
}
19 changes: 10 additions & 9 deletions crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ use std::path::Path;

use ctor::ctor;
use frida_gum::interceptor::{InvocationContext, InvocationListener};
use frida_gum::{interceptor::Interceptor, Gum, Module};
use frida_gum::{interceptor::Interceptor, Gum};
use lazy_static::lazy_static;

use crate::config::{Config, FileConfig};
use crate::config::{Config, ReadFromFile};
use crate::core::process_script;
use crate::v8_exports::V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL_SYMBOL;
use crate::identifier::Identifier;
use crate::v8_sys::{V8Context, V8Source};

mod config;
mod core;
mod identifier;
mod matcher;
mod processor;
mod source;
mod v8_exports;
mod v8_sys;

lazy_static! {
Expand Down Expand Up @@ -48,11 +48,12 @@ impl InvocationListener for V8ScriptCompilerCompileFunctionInternalListener {

#[ctor]
fn init() {
// Fix no output in the Windows GUI subsystem programs
// See also: [#11](https://github.com/ShellWen/v8_killer/issues/11)
#[cfg(target_os = "windows")]
unsafe {
use windows::Win32::System::Console::{AttachConsole, ATTACH_PARENT_PROCESS};

// fix [#11](https://github.com/ShellWen/v8_killer/issues/11)
let _ = AttachConsole(ATTACH_PARENT_PROCESS);
}

Expand All @@ -72,10 +73,10 @@ fn init() {

interceptor.begin_transaction();

let v8_script_compiler_compile_function_internal = Module::find_export_by_name(
None,
V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL_SYMBOL,
);
let v8_script_compiler_compile_function_internal = unsafe { CONFIG.as_ref().unwrap() }
.identifiers
.V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL
.identify();

match v8_script_compiler_compile_function_internal {
None => {
Expand Down
12 changes: 6 additions & 6 deletions crates/core/src/matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ use serde::Deserialize;

use crate::source::Source;

pub(crate) trait SourceMatcherTrait {
pub(crate) trait SourceMatcher {
fn matches(&self, resource: &Source) -> bool;
}

#[derive(Deserialize, Debug)]
#[serde(tag = "type")]
pub enum SourceMatcher {
pub(crate) enum SourceMatcherEnum {
#[serde(rename = "resource-name-keyword")]
ResourceNameKeywordMatcher(ResourceNameKeywordMatcher),
}

impl SourceMatcher {
pub fn matches(&self, source: &Source) -> bool {
impl SourceMatcher for SourceMatcherEnum {
fn matches(&self, source: &Source) -> bool {
match self {
SourceMatcher::ResourceNameKeywordMatcher(matcher) => matcher.matches(source),
SourceMatcherEnum::ResourceNameKeywordMatcher(matcher) => matcher.matches(source),
}
}
}
Expand All @@ -26,7 +26,7 @@ pub struct ResourceNameKeywordMatcher {
pub keyword: String,
}

impl SourceMatcherTrait for ResourceNameKeywordMatcher {
impl SourceMatcher for ResourceNameKeywordMatcher {
fn matches(&self, source: &Source) -> bool {
source.resource_name.contains(&self.keyword)
}
Expand Down
26 changes: 0 additions & 26 deletions crates/core/src/v8_exports.rs

This file was deleted.

44 changes: 30 additions & 14 deletions crates/core/src/v8_sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

use std::ffi::{c_char, c_int, c_void};

use frida_gum::Module;

use crate::v8_exports::{
V8_CONTEXT_GET_ISOLATE_SYMBOL, V8_STRING_NEW_FROM_UTF8_SYMBOL, V8_STRING_UTF8LENGTH_SYMBOL,
V8_STRING_WRITE_UTF8_SYMBOL,
};
use crate::identifier::Identifier;
use crate::CONFIG;

pub(crate) type V8Context = c_void;
pub(crate) type V8Isolate = c_void;
Expand Down Expand Up @@ -80,8 +76,13 @@ type v8__String__NewFromUtf8 = unsafe extern "C" fn(
) -> V8Local<V8String>;

pub(crate) unsafe fn v8_context_get_isolate(context: *const V8Context) -> *const V8Isolate {
let v8_context_get_isolate_ptr =
Module::find_export_by_name(None, V8_CONTEXT_GET_ISOLATE_SYMBOL).unwrap();
let v8_context_get_isolate_ptr = CONFIG
.as_ref()
.unwrap()
.identifiers
.V8_CONTEXT_GET_ISOLATE
.identify()
.unwrap();
let v8_context_get_isolate_func: v8__Context__GetIsolate =
std::mem::transmute(v8_context_get_isolate_ptr.0);

Expand All @@ -92,8 +93,13 @@ pub(super) unsafe fn v8_string_utf8_length(
this: *const V8String,
isolate: *const V8Isolate,
) -> usize {
let v8_string_utf8_length_ptr =
Module::find_export_by_name(None, V8_STRING_UTF8LENGTH_SYMBOL).unwrap();
let v8_string_utf8_length_ptr = CONFIG
.as_ref()
.unwrap()
.identifiers
.V8_STRING_UTF8LENGTH
.identify()
.unwrap();
let v8_string_utf8_length_func: v8__String__Utf8Length =
std::mem::transmute(v8_string_utf8_length_ptr.0);

Expand All @@ -108,8 +114,13 @@ pub(crate) unsafe fn v8_string_write_utf8(
nchars_ref: *mut usize,
options: c_int,
) -> c_int {
let v8_string_write_utf8_ptr =
Module::find_export_by_name(None, V8_STRING_WRITE_UTF8_SYMBOL).unwrap();
let v8_string_write_utf8_ptr = CONFIG
.as_ref()
.unwrap()
.identifiers
.V8_STRING_WRITE_UTF8
.identify()
.unwrap();
let v8_string_write_utf8_func: v8__String__WriteUtf8 =
std::mem::transmute(v8_string_write_utf8_ptr.0);

Expand All @@ -122,8 +133,13 @@ pub(crate) unsafe fn v8_string_new_from_utf8(
new_type: i32,
length: i32,
) -> V8Local<V8String> {
let v8_string_new_from_utf8_ptr =
Module::find_export_by_name(None, V8_STRING_NEW_FROM_UTF8_SYMBOL).unwrap();
let v8_string_new_from_utf8_ptr = CONFIG
.as_ref()
.unwrap()
.identifiers
.V8_STRING_NEW_FROM_UTF8
.identify()
.unwrap();
let v8_string_new_from_utf8_func: v8__String__NewFromUtf8 =
std::mem::transmute(v8_string_new_from_utf8_ptr.0);

Expand Down
25 changes: 25 additions & 0 deletions examples/configs/simple.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
[identifiers]
V8_SCRIPT_COMPILER_COMPILE_FUNCTION_INTERNAL = [{ type = "symbol", symbols = [
"""_ZN2v814ScriptCompiler23CompileFunctionInternalENS_5LocalINS_\
7ContextEEEPNS0_6SourceEmPNS1_INS_6StringEEEmPNS1_INS_6ObjectEEE\
NS0_14CompileOptionsENS0_13NoCacheReasonEPNS1_INS_14ScriptOrModu\
leEEE""",
"""?CompileFunctionInternal@ScriptCompiler@v8@@CA?AV?$MaybeLocal\
@VFunction@v8@@@2@V?$Local@VContext@v8@@@2@PEAVSource@12@_KQEAV?\
$Local@VString@v8@@@2@2QEAV?$Local@VObject@v8@@@2@W4CompileOptio\
ns@12@W4NoCacheReason@12@PEAV?$Local@VScriptOrModule@v8@@@2@@Z"""] }]
V8_STRING_UTF8LENGTH = [{ type = "symbol", symbols = [
"""_ZNK2v86String10Utf8LengthEPNS_7IsolateE""",
"""?Utf8Length@String@v8@@QEBAHPEAVIsolate@2@@Z"""] }]
V8_STRING_WRITE_UTF8 = [{ type = "symbol", symbols = [
"""_ZNK2v86String9WriteUtf8EPNS_7IsolateEPciPii""",
"""?WriteUtf8@String@v8@@QEBAHPEAVIsolate@2@PEADHPEAHH@Z"""] }]
V8_CONTEXT_GET_ISOLATE = [{ type = "symbol", symbols = [
"""_ZN2v87Context10GetIsolateEv""",
"""?GetIsolate@Context@v8@@QEAAPEAVIsolate@2@XZ"""] }]
V8_STRING_NEW_FROM_UTF8 = [{ type = "symbol", symbols = [
"""_ZN2v86String11NewFromUtf8EPNS_7IsolateEPKcNS_13NewStringTypeEi""",
"""?NewFromUtf8@String@v8@@SA?AV?$MaybeLocal@VString@v8@@@2@PEAV\
Isolate@2@PEBDW4NewStringType@2@H@Z"""] }]


[rules.hook_console_log]
matcher = { type = "resource-name-keyword", keyword = "hello_world.js" }

Expand Down

0 comments on commit eb6802a

Please sign in to comment.