From 2c4674eb42119147b7094e7314fb9083bcf18329 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov <alexander@vlang.io> Date: Tue, 2 Feb 2021 09:14:34 +0100 Subject: [PATCH] cgen: obfuscate functions --- cmd/tools/vfmt.v | 4 ++-- vlib/v/fmt/fmt.v | 7 +++++-- vlib/v/gen/cgen.v | 43 +++++++++++++++++++++++++++++++++++++++++++ vlib/v/gen/fn.v | 30 ++++++++++++++++++++++++++++++ vlib/v/pref/pref.v | 1 + 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/cmd/tools/vfmt.v b/cmd/tools/vfmt.v index 90c5a9493b..fcf34ef32d 100644 --- a/cmd/tools/vfmt.v +++ b/cmd/tools/vfmt.v @@ -165,7 +165,7 @@ fn (foptions &FormatOptions) format_file(file string) { parent: 0 }) // checker.check(file_ast) - formatted_content := fmt.fmt(file_ast, table, foptions.is_debug) + formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug) file_name := os.file_name(file) ulid := rand.ulid() vfmt_output_path := os.join_path(vtmp_folder, 'vfmt_${ulid}_$file_name') @@ -189,7 +189,7 @@ fn (foptions &FormatOptions) format_pipe() { parent: 0 }) // checker.check(file_ast) - formatted_content := fmt.fmt(file_ast, table, foptions.is_debug) + formatted_content := fmt.fmt(file_ast, table, prefs, foptions.is_debug) print(formatted_content) if foptions.is_verbose { eprintln('fmt.fmt worked and $formatted_content.len bytes were written to stdout.') diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index c0abb83edf..9407aa48bf 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -7,6 +7,7 @@ import v.ast import v.table import strings import v.util +import v.pref const ( bs = '\\' @@ -46,9 +47,10 @@ pub mut: inside_lambda bool inside_const bool is_mbranch_expr bool // math a { x...y { } } + pref &pref.Preferences } -pub fn fmt(file ast.File, table &table.Table, is_debug bool) string { +pub fn fmt(file ast.File, table &table.Table, pref &pref.Preferences, is_debug bool) string { mut f := Fmt{ out: strings.new_builder(1000) out_imports: strings.new_builder(200) @@ -56,6 +58,7 @@ pub fn fmt(file ast.File, table &table.Table, is_debug bool) string { indent: 0 file: file is_debug: is_debug + pref: pref } f.process_file_imports(file) f.set_current_module_name('main') @@ -323,7 +326,7 @@ pub fn (mut f Fmt) stmts(stmts []ast.Stmt) { mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.Stmt{} } f.indent++ for stmt in stmts { - if f.should_insert_newline_before_stmt(stmt, prev_stmt) { + if !f.pref.building_v && f.should_insert_newline_before_stmt(stmt, prev_stmt) { f.out.writeln('') } f.stmt(stmt) diff --git a/vlib/v/gen/cgen.v b/vlib/v/gen/cgen.v index 63c06b9d4e..ecfa9852f5 100644 --- a/vlib/v/gen/cgen.v +++ b/vlib/v/gen/cgen.v @@ -148,6 +148,7 @@ mut: timers &util.Timers = util.new_timers(false) force_main_console bool // true when [console] used on fn main() as_cast_type_names map[string]string // table for type name lookup in runtime (for __as_cast) + obf_table map[string]string } pub fn cgen(files []ast.File, table &table.Table, pref &pref.Preferences) string { @@ -427,6 +428,29 @@ pub fn (mut g Gen) init() { if g.pref.is_livemain || g.pref.is_liveshared { g.generate_hotcode_reloading_declarations() } + // Obfuscate only functions in the main module for now. + // Generate the obf_table. + if g.pref.obfuscate { + mut i := 0 + // fns + for key, f in g.table.fns { + if f.mod != 'main' && key != 'main' { // !key.starts_with('main.') { + continue + } + g.obf_table[key] = '_f$i' + i++ + } + // methods + for type_sym in g.table.types { + if type_sym.mod != 'main' { + continue + } + for method in type_sym.methods { + g.obf_table[type_sym.name + '.' + method.name] = '_f$i' + i++ + } + } + } } pub fn (mut g Gen) finish() { @@ -3816,6 +3840,14 @@ fn (mut g Gen) ident(node ast.Ident) { } } } + } else if node_info is ast.IdentFn { + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') { + key := node.name + g.write('/* obf identfn: $key */') + name = g.obf_table[key] or { + panic('cgen: obf name "$key" not found, this should never happen') + } + } } g.write(g.get_ternary_name(name)) } @@ -5688,6 +5720,17 @@ fn (mut g Gen) go_stmt(node ast.GoStmt, joinable bool) string { name = fsym.name } name = util.no_dots(name) + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') { + mut key := expr.name + if expr.is_method { + sym := g.table.get_type_symbol(expr.receiver_type) + key = sym.name + '.' + expr.name + } + g.write('/* obf go: $key */') + name = g.obf_table[key] or { + panic('cgen: obf name "$key" not found, this should never happen') + } + } g.writeln('// go') wrapper_struct_name := 'thread_arg_' + name wrapper_fn_name := name + '_thread_wrapper' diff --git a/vlib/v/gen/fn.v b/vlib/v/gen/fn.v index c6a95b2b89..6936cf65c5 100644 --- a/vlib/v/gen/fn.v +++ b/vlib/v/gen/fn.v @@ -78,6 +78,18 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) { name += '_' + gen_name } } + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') + && name != 'main__main'&& node.name != 'str' { + mut key := node.name + if node.is_method { + sym := g.table.get_type_symbol(node.receiver.typ) + key = sym.name + '.' + node.name + } + g.writeln('/* obf: $key */') + name = g.obf_table[key] or { + panic('cgen: fn_decl: obf name "$key" not found, this should never happen') + } + } // if g.pref.show_cc && it.is_builtin { // println(name) // } @@ -457,6 +469,16 @@ fn (mut g Gen) method_call(node ast.CallExpr) { name = 'map_keys_1' } } + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') + && node.name != 'str' { + sym := g.table.get_type_symbol(node.receiver_type) + // key = g.cc_type2(node.receiver.typ) + '.' + node.name + key := sym.name + '.' + node.name + g.write('/* obf method call: $key */') + name = g.obf_table[key] or { + panic('cgen: obf name "$key" not found, this should never happen') + } + } // Check if expression is: arr[a..b].clone(), arr[a..].clone() // if so, then instead of calling array_clone(&array_slice(...)) // call array_clone_static(array_slice(...)) @@ -620,6 +642,14 @@ fn (mut g Gen) fn_call(node ast.CallExpr) { } else { name = c_name(name) } + // Obfuscate only functions in the main module for now + if g.pref.obfuscate && g.cur_mod.name == 'main' && name.starts_with('main__') { + key := node.name + g.write('/* obf call: $key */') + name = g.obf_table[key] or { + panic('cgen: obf name "$key" not found, this should never happen') + } + } for i, generic_type in node.generic_types { // Using _T_ to differentiate between get<string> and get_string // `foo<int>()` => `foo_T_int()` diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 81beda2619..a15b183f72 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -47,6 +47,7 @@ const ( 'cflags', 'path'] ) +[ref_only] pub struct Preferences { pub mut: os OS // the OS to compile for