Repository: revsic/cpp-obfuscator Branch: master Commit: 3dd832715270 Files: 29 Total size: 41.0 KB Directory structure: gitextract_9t2uq1pg/ ├── .gitignore ├── .gitmodules ├── 3RD-PARTY.md ├── LICENSE ├── README.md ├── azure-pipelines.yml ├── obfuscator/ │ ├── obfs/ │ │ ├── fsm.hpp │ │ ├── random.hpp │ │ ├── sequence.hpp │ │ └── string.hpp │ └── obfuscator.hpp ├── obfuscator.hpp ├── sample/ │ ├── CMakeLists.txt │ ├── random.cpp │ ├── state_machine.cpp │ └── string_obfs.cpp ├── script/ │ ├── Dockerfile.bionic │ ├── __init__.py │ ├── azure-pipelines-template-mac.yml │ ├── azure-pipelines-template-unix.yml │ ├── azure-pipelines-template-win.yml │ ├── merge.py │ └── string_obfs_tester.py └── test/ ├── CMakeLists.txt ├── impl/ │ ├── fsm.cpp │ ├── random.cpp │ ├── sequence.cpp │ └── string.cpp └── main.cpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # editor .vscode # build build # cl with debug option *.ilk *.obj *.pdb # sample program *.exe # python cache __pycache__ ================================================ FILE: .gitmodules ================================================ [submodule "external/Catch2"] path = external/Catch2 url = https://github.com/catchorg/Catch2 ================================================ FILE: 3RD-PARTY.md ================================================ cpp-obfuscator uses Catch2 for testing obfuscator modules Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 YoungJoong Kim 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. ================================================ FILE: README.md ================================================ # cpp-obfuscator [![License](https://img.shields.io/badge/Licence-MIT-blue.svg)](https://github.com/revsic/cpp-obfuscator/blob/master/LICENSE) [![Build Status](https://dev.azure.com/revsic99/cpp-obfuscator/_apis/build/status/revsic.cpp-obfuscator?branchName=master)](https://dev.azure.com/revsic99/cpp-obfuscator/_build/latest?definitionId=3&branchName=master) C++ implementation of compile time obfuscator ## Compiler Support | Compiler | Version | | -- | -- | | Visual Studio | 2019 | | Clang++ | 8.0 | | g++ | 7.3 | | Apple Clang | Mojave | ## Usage Use existing single header [obfuscator.hpp](./obfuscator.hpp) or run [script](./script/merge.py) to merge multiple headers in directory [obfuscator](./obfuscator). ```bash python -m script.merge ``` Include [obfuscator.hpp](./obfuscator.hpp) to use it. ```C++ #include "../obfuscator.hpp" template constexpr char xor_(char c) { return c ^ key; } std::cout << obfs::make_string, xor_<0x50>>("Hello World !\n").decode(); ``` ## String Compile time string obfuscator. No more raw string in binary, sample [string_obfuscator](./sample/string_obfs.cpp). 0. Sample encoder, decoder ```C++ template constexpr char xor_(char c) { return c ^ key; } template constexpr char add(char c) { return c + Key; } template constexpr char comp(char c) { return f(g(c)); } ``` 1. Single encoder, decoder. ```C++ std::cout << obfs::make_string, xor_<0x50>>("Hello World !\n").decode(); ``` 2. Multiple encoder, decoder and random selection. ```C++ using table = obfs::make_table< obfs::encoder_seq, add<10>, comp, add<10>>>, obfs::decoder_seq, add<-10>, comp, xor_<0x50>>>>; std::cout << obfs::make_string("Hello World !\n").decode(); ``` 3. Multiple encoder, decoder as pair. ```C++ using table = obfs::make_pair_table< obfs::encoder_pair, xor_<0x50>>, obfs::encoder_pair, add<-10>>, obfs::encoder_pair, add<10>>, comp, xor_<0x50>>> >; std::cout << obfs::make_string
("Hello World !\n").decode(); ``` 4. String obfuscator macro. ```C++ MAKE_STRING(str, "Hello World !\n", table); std::cout << str.decode(); ``` ## Finite state machine Compile time finite state machine based routine obfuscator, sample [state_machine](./sample/state_machine.cpp). 0. Make state table. ```C++ using namespace obfs; using machine = StateMachine< Stage, Next>, Stage>, Stage>, Stage, Next>, Stage>>; ``` 1. Run state machine, each execution returns next state. ```C++ auto next1 = machine::run(state1{}, event5{}); // dummy1 executed auto next2 = machine::run(next1, event2{}); auto next3 = machine::run(next2, event3{}); // dummy2 executed auto next4 = machine::run(next3, Trigger{}); // action executed ``` ================================================ FILE: azure-pipelines.yml ================================================ jobs: - template: script/azure-pipelines-template-mac.yml parameters: name: macOS vmImage: macOS-10.14 - template: script/azure-pipelines-template-unix.yml parameters: name: Linux vmImage: ubuntu-16.04 - template: script/azure-pipelines-template-win.yml parameters: name: Windows vmImage: windows-2019 ================================================ FILE: obfuscator/obfs/fsm.hpp ================================================ #ifndef OBFS_FINITE_STATE_MACHINE #define OBFS_FINITE_STATE_MACHINE #include "sequence.hpp" #include namespace obfs { void FreeAction() {} template struct Next { using event = Event; using state = State; constexpr static void(*action)() = Action; }; struct None {}; template struct Stage { using state = State; template using act = std::conditional_t< std::is_same_v, NextInfo, Pass>; template using next = typename First...>::type; }; template struct next_stage { using type = typename Stage_::template next; }; template struct next_stage { using type = None; }; template struct action_invoker { static auto action() { State::action(); return typename State::state{}; } }; template <> struct action_invoker { static auto action() { return None{}; } }; template struct StateMachine { template using filter = std::conditional_t< std::is_same_v, StageT, Pass>; template using find = typename First...>::type; template using next_t = typename next_stage, Event>::type; template static auto run(State state, Event event) { using next_state = next_t, std::decay_t>; return action_invoker::action(); } }; } #endif ================================================ FILE: obfuscator/obfs/random.hpp ================================================ #ifndef COMPILE_TIME_RANDOM #define COMPILE_TIME_RANDOM namespace obfs { using size_t = decltype(sizeof(void*)); constexpr char TIME[] = __TIME__; constexpr int digit(char c) { return c - '0'; } constexpr size_t SEED = digit(TIME[7]) + digit(TIME[6]) * 10 + digit(TIME[4]) * 60 + digit(TIME[3]) * 600 + digit(TIME[1]) * 3600 + digit(TIME[0]) * 36000; template struct Xorshiftplus { using prev = Xorshiftplus; constexpr static size_t update() { constexpr size_t x = prev::state0 ^ (prev::state0 << 23); constexpr size_t y = prev::state1; return x ^ y ^ (x >> 17) ^ (y >> 26); } constexpr static size_t state0 = prev::state1; constexpr static size_t state1 = update(); constexpr static size_t value = state0 + state1; }; template struct Xorshiftplus { constexpr static size_t state0 = Seed; constexpr static size_t state1 = Seed << 1; constexpr static size_t value = state0 + state1; }; template constexpr size_t RAND_VAL = Xorshiftplus::value % Mod; } #define MAKE_RAND_VAL(MOD) obfs::RAND_VAL<__LINE__, MOD> #endif ================================================ FILE: obfuscator/obfs/sequence.hpp ================================================ #ifndef COMPILE_TIME_SEQUENCE #define COMPILE_TIME_SEQUENCE #include namespace obfs { template struct TypeVal { using value_type = T; constexpr static T value = Val; }; struct Nothing {}; template struct Sequence { using value = TypeVal; using next = Sequence; constexpr static std::size_t size = 1 + sizeof...(Others); template using index = std::conditional_t>; }; template struct Sequence { using value = TypeVal; constexpr static std::size_t size = 1; template using index = std::conditional_t; }; template struct TypeSeq { using type = T; using next = TypeSeq; constexpr static std::size_t size = 1 + sizeof...(Ts); template using index = std::conditional_t>; }; template struct TypeSeq { using type = T; constexpr static std::size_t size = 1; template using index = std::conditional_t; }; template struct MinVal { constexpr static std::size_t value = Val < MinVal::value ? Val : MinVal::value; }; template struct MinVal { constexpr static std::size_t value = Val; }; template struct SeqPack { constexpr static std::size_t size = MinVal::value; template using getter = typename U::template index; template using index = TypeSeq...>; }; struct Pass {}; template struct First { using type = std::conditional_t< std::is_same_v, typename First::type, T>; }; template struct First { using type = std::conditional_t< std::is_same_v, IfAllPass, T>; }; } #endif ================================================ FILE: obfuscator/obfs/string.hpp ================================================ #ifndef OBFS_STRING #define OBFS_STRING #include "random.hpp" #include "sequence.hpp" #include namespace obfs { using Encoder = char(*)(char); using Decoder = char(*)(char); template class String { public: template constexpr String(char const* str, std::index_sequence): str{ encoder(str[Idx])... } { // Do Nothing } inline char const* decode() const { for (char& chr : str) { chr = decoder(chr); } return str; } private: mutable char str[size]; }; template constexpr auto make_string(char const (&str)[size]) { return String(str, std::make_index_sequence()); } template using encoder_seq = Sequence; template using decoder_seq = Sequence; template using make_table = SeqPack; template using encoder_pair = Sequence; template using make_pair_table = TypeSeq; template constexpr auto make_string(char const(&str)[size]) { using pair = typename Table::template index; constexpr Encoder encoder = pair::template index<0>::value; constexpr Decoder decoder = pair::template index<1>::value; return make_string(str); } } #define MAKE_STRING(Var, String, ...) constexpr auto Var = obfs::make_string<__VA_ARGS__>(String); #endif ================================================ FILE: obfuscator/obfuscator.hpp ================================================ #ifndef OBFUSCATOR #define OBFUSCATOR #include "obfs/fsm.hpp" #include "obfs/random.hpp" #include "obfs/sequence.hpp" #include "obfs/string.hpp" #endif ================================================ FILE: obfuscator.hpp ================================================ #ifndef OBFUSCATOR_HPP #define OBFUSCATOR_HPP #include #include #define COMPILE_TIME_SEQUENCE #define OBFS_FINITE_STATE_MACHINE #define COMPILE_TIME_RANDOM #define MAKE_RAND_VAL(MOD) obfs::RAND_VAL<__LINE__, MOD> #define OBFS_STRING #define MAKE_STRING(Var, String, ...) constexpr auto Var = obfs::make_string<__VA_ARGS__>(String); namespace obfs { template struct TypeVal { using value_type = T; constexpr static T value = Val; }; struct Nothing {}; template struct Sequence { using value = TypeVal; using next = Sequence; constexpr static std::size_t size = 1 + sizeof...(Others); template using index = std::conditional_t>; }; template struct Sequence { using value = TypeVal; constexpr static std::size_t size = 1; template using index = std::conditional_t; }; template struct TypeSeq { using type = T; using next = TypeSeq; constexpr static std::size_t size = 1 + sizeof...(Ts); template using index = std::conditional_t>; }; template struct TypeSeq { using type = T; constexpr static std::size_t size = 1; template using index = std::conditional_t; }; template struct MinVal { constexpr static std::size_t value = Val < MinVal::value ? Val : MinVal::value; }; template struct MinVal { constexpr static std::size_t value = Val; }; template struct SeqPack { constexpr static std::size_t size = MinVal::value; template using getter = typename U::template index; template using index = TypeSeq...>; }; struct Pass {}; template struct First { using type = std::conditional_t< std::is_same_v, typename First::type, T>; }; template struct First { using type = std::conditional_t< std::is_same_v, IfAllPass, T>; }; } namespace obfs { void FreeAction() {} template struct Next { using event = Event; using state = State; constexpr static void(*action)() = Action; }; struct None {}; template struct Stage { using state = State; template using act = std::conditional_t< std::is_same_v, NextInfo, Pass>; template using next = typename First...>::type; }; template struct next_stage { using type = typename Stage_::template next; }; template struct next_stage { using type = None; }; template struct action_invoker { static auto action() { State::action(); return typename State::state{}; } }; template <> struct action_invoker { static auto action() { return None{}; } }; template struct StateMachine { template using filter = std::conditional_t< std::is_same_v, StageT, Pass>; template using find = typename First...>::type; template using next_t = typename next_stage, Event>::type; template static auto run(State state, Event event) { using next_state = next_t, std::decay_t>; return action_invoker::action(); } }; } namespace obfs { using size_t = decltype(sizeof(void*)); constexpr char TIME[] = __TIME__; constexpr int digit(char c) { return c - '0'; } constexpr size_t SEED = digit(TIME[7]) + digit(TIME[6]) * 10 + digit(TIME[4]) * 60 + digit(TIME[3]) * 600 + digit(TIME[1]) * 3600 + digit(TIME[0]) * 36000; template struct Xorshiftplus { using prev = Xorshiftplus; constexpr static size_t update() { constexpr size_t x = prev::state0 ^ (prev::state0 << 23); constexpr size_t y = prev::state1; return x ^ y ^ (x >> 17) ^ (y >> 26); } constexpr static size_t state0 = prev::state1; constexpr static size_t state1 = update(); constexpr static size_t value = state0 + state1; }; template struct Xorshiftplus { constexpr static size_t state0 = Seed; constexpr static size_t state1 = Seed << 1; constexpr static size_t value = state0 + state1; }; template constexpr size_t RAND_VAL = Xorshiftplus::value % Mod; } namespace obfs { using Encoder = char(*)(char); using Decoder = char(*)(char); template class String { public: template constexpr String(char const* str, std::index_sequence): str{ encoder(str[Idx])... } { // Do Nothing } inline char const* decode() const { for (char& chr : str) { chr = decoder(chr); } return str; } private: mutable char str[size]; }; template constexpr auto make_string(char const (&str)[size]) { return String(str, std::make_index_sequence()); } template using encoder_seq = Sequence; template using decoder_seq = Sequence; template using make_table = SeqPack; template using encoder_pair = Sequence; template using make_pair_table = TypeSeq; template constexpr auto make_string(char const(&str)[size]) { using pair = typename Table::template index; constexpr Encoder encoder = pair::template index<0>::value; constexpr Decoder decoder = pair::template index<1>::value; return make_string(str); } } #endif ================================================ FILE: sample/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(sample) set(CMAKE_CXX_STANDARD 17) add_executable(string_obfs string_obfs.cpp) add_executable(state_machine state_machine.cpp) add_executable(random random.cpp) ================================================ FILE: sample/random.cpp ================================================ #include "../obfuscator.hpp" #include int main() { std::cout << MAKE_RAND_VAL(100) << std::endl; return 0; } ================================================ FILE: sample/state_machine.cpp ================================================ #include "../obfuscator.hpp" #include #define STATE(Name) struct Name {}; #define EVENT(Name) struct Name {}; STATE(Final); EVENT(Trigger); STATE(state1); STATE(state2); STATE(state3); STATE(state4); STATE(state5); EVENT(event1); EVENT(event2); EVENT(event3); EVENT(event4); EVENT(event5); struct Action { static bool trigged; static void action() { trigged = true; std::cout << "Trigged" << std::endl; } }; bool Action::trigged = true; struct Dummy { static int dummy; static void dummy1() { dummy += 10; std::cout << "Dummy1" << std::endl; } static void dummy2() { dummy *= 20; std::cout << "Dummy2" << std::endl; } static void dummy3() { std::exit(1); } }; int Dummy::dummy = 0; int main() { using namespace obfs; using machine = StateMachine< Stage, Next>, Stage>, Stage>, Stage, Next>, Stage>>; auto next1 = machine::run(state1{}, event5{}); auto next2 = machine::run(next1, event2{}); auto next3 = machine::run(next2, event3{}); auto next4 = machine::run(next3, Trigger{}); return 0; } ================================================ FILE: sample/string_obfs.cpp ================================================ #include "../obfuscator.hpp" #include template constexpr char xor_(char c) { return c ^ key; } template constexpr char add(char c) { return c + Key; } template constexpr char comp(char c) { return f(g(c)); } int main() { using table = obfs::make_table< obfs::encoder_seq, add<10>, comp, add<10>>>, obfs::decoder_seq, add<-10>, comp, xor_<0x50>>>>; MAKE_STRING(str, "Hello World !", table); std::cout << str.decode() << std::endl; } ================================================ FILE: script/Dockerfile.bionic ================================================ FROM ubuntu:18.04 RUN apt-get update -yq && apt-get install -yq build-essential cmake python3.6 python3.6-dev python3-pip python3-setuptools python3-wheel RUN echo `g++ --version` ADD . /app # Run UnitTest WORKDIR /app/test/build RUN cmake .. && \ make -j `nproc` && \ ./unittest # Run Additional Test WORKDIR /app/sample/build RUN cmake .. && \ make -j `nproc` WORKDIR /app RUN python3 -m script.merge && \ python3 -m script.string_obfs_tester ./sample/build/string_obfs "Hello World !" ================================================ FILE: script/__init__.py ================================================ ================================================ FILE: script/azure-pipelines-template-mac.yml ================================================ jobs: - job: ${{ parameters.name }} pool: vmImage: ${{ parameters.vmImage }} steps: # Initialize - script: git submodule update --init displayName: Initialize submodule # UnitTest - task: CMake@1 inputs: workingDirectory: ./test/build cmakeArgs: ../ displayName: CMake unittest - script: cd ./test/build && make; displayName: GNU Make unittest - script: ./test/build/unittest displayName: Run unittest # Additional tests - task: UsePythonVersion@0 inputs: versionSpec: 3.6 architecture: 'x64' - script: python -m script.merge displayName: Remerge obfuscator.hpp - task: CMake@1 inputs: workingDirectory: ./sample/build cmakeArgs: ../ displayName: CMake sample - script: cd ./sample/build && make; displayName: GNU Make sample - script: python -m script.string_obfs_tester ./sample/build/string_obfs "Hello World !" displayName: String OBFS test ================================================ FILE: script/azure-pipelines-template-unix.yml ================================================ jobs: - job: ${{ parameters.name }} pool: vmImage: ${{ parameters.vmImage }} steps: - script: git submodule update --init displayName: initialize submodule - script: docker build -f script/Dockerfile.bionic -t cpp_obfuscator . displayName: run docker-bionic ================================================ FILE: script/azure-pipelines-template-win.yml ================================================ jobs: - job: ${{ parameters.name }} pool: vmImage: ${{ parameters.vmImage }} steps: # Initialize - script: git submodule update --init displayName: Initialize submodule # UnitTest - task: CMake@1 inputs: workingDirectory: .\test\build cmakeArgs: ..\ displayName: CMake unittest - task: MSBuild@1 inputs: solution: .\test\build\unittest.sln displayName: MSBuild unittest - script: .\test\build\Debug\unittest.exe displayName: Start unittest # Additional tests - task: UsePythonVersion@0 inputs: versionSpec: 3.6 architecture: 'x64' - script: python -m script.merge displayName: Remerge obfuscator.hpp - task: CMake@1 inputs: workingDirectory: .\sample\build cmakeArgs: ..\ displayName: CMake sample - task: MSBuild@1 inputs: solution: .\sample\build\sample.sln displayName: MSBuild sample - script: python -m script.string_obfs_tester .\sample\build\Debug\string_obfs.exe "Hello World !" displayName: String OBFS test ================================================ FILE: script/merge.py ================================================ import os import re import sys class Format(object): hpp = '''\ #ifndef {0} #define {0} {1} {2} {3} #endif''' @classmethod def hpp_beutifier(cls, source): out = '' n_blank = 0 for line in source.split('\n'): if line == '' or line.isspace(): n_blank += 1 else: if n_blank > 2: n_blank = 2 out += '\n' * n_blank n_blank = 0 out += line + '\n' return out class ReSupport(object): r_guard = re.compile(r'(#ifndef|#endif)') r_include_dep = re.compile(r'#include "(.+?)"') r_include = re.compile(r'#include <(.+?)>') r_define = re.compile(r'#define (.+)') @classmethod def guard(cls, inp): return cls.r_guard.findall(inp) @classmethod def include_dep(cls, inp): return cls.r_include_dep.findall(inp) @classmethod def include(cls, inp): return cls.r_include.findall(inp) @classmethod def define(cls, inp): return cls.r_define.findall(inp) class SourceInfo(object): def __init__(self): self.out = '' self.deps = [] self.includes = [] self.defines = [] @classmethod def set_with(cls, out, deps, includes, defines): obj = cls() obj.out = out obj.deps = deps obj.includes = includes obj.defines = defines return obj @classmethod def read_file(cls, path): obj = cls() with open(path) as f: for line in f.readlines(): if len(ReSupport.guard(line)) > 0: continue include_name = ReSupport.include_dep(line) if len(include_name) > 0: obj.deps.append(include_name[0]) continue include_name = ReSupport.include(line) if len(include_name) > 0: obj.includes.append(include_name[0]) continue define_name = ReSupport.define(line) if len(define_name) > 0: obj.defines.append(define_name[0]) continue obj.out += line return obj def __add__(self, other): out = self.out + other.out deps = self.deps + other.deps includes = self.includes + other.includes defines = self.defines + other.defines return SourceInfo.set_with(out, deps, includes, defines) def file_list(dirname, ban_dir=[]): files = [] if isinstance(ban_dir, str): ban_dir = [ban_dir] for name in os.listdir(dirname): full_path = os.path.join(dirname, name) if os.path.isfile(full_path): files.append(full_path) elif os.path.isdir(full_path) and name not in ban_dir: files += file_list(full_path) return files def in_endswith(name, files): for f in files: if f.endswith(name): return f return None def order_dep(deps, files, done): info = SourceInfo() for dep in deps: if in_endswith(dep, done) is None: path = in_endswith(dep.split('/')[-1], files) if path is not None: new = SourceInfo.read_file(path) dep_new = order_dep(new.deps, files, done) info += dep_new + new done.append(path) return info def none_preproc(dirname): if not os.path.exists(dirname): return [], '' dep = [] out = '' includes = '' for files in os.listdir(dirname): with open(os.path.join(dirname, files)) as f: lines = f.readlines() if lines[0].startswith('#ifndef') \ and lines[1].startswith('#define') \ and lines[-1].startswith('#endif'): lines = lines[2:-1] data = ''.join(lines) include_idx = data.find('// merge:np_include') if include_idx != -1: start_idx = include_idx + len('// merge:np_include') end_idx = data.find('// merge:end', include_idx) includes += data[start_idx:end_idx] data = data[end_idx + len('// merge:end'):] include_idx = data.find('// merge:include') if include_idx != -1: start_idx = include_idx + len('// merge:include') end_idx = data.find('// merge:end', include_idx) for line in data[start_idx:end_idx].split('\n'): res = ReSupport.include(line) if len(res) > 0: dep += res includes += line + '\n' data = data[end_idx + len('// merge:end'):] dep.append(files) out += data return dep, includes + out def merge(dirname): done = [] info = SourceInfo() files = file_list(dirname, 'platform') preproc_dep, info.out = \ none_preproc(os.path.join(dirname, 'platform')) for full_path in files: if full_path not in done: source = SourceInfo.read_file(full_path) dep = order_dep(source.deps, files, done) info += dep + source done.append(full_path) return info, preproc_dep def write_hpp(outfile, merged): info, preproc_dep = merged dep_check = lambda file: not any(file.endswith(dep) for dep in preproc_dep) idx = outfile.rfind('/') if idx > -1: outfile = outfile[idx+1:] guard_name = outfile.upper().replace('.', '_') unique_include = [] for include in info.includes: if include not in unique_include and dep_check(include): unique_include.append(include) includes = '\n'.join( '#include <{}>'.format(x) for x in sorted(unique_include)) + '\n' defines = '\n'.join( '#define {}'.format(x) for x in info.defines) + '\n' out = Format.hpp.format(guard_name, includes, defines, info.out) out = Format.hpp_beutifier(out) with open(outfile, 'w') as f: f.write(out) if __name__ == "__main__": if len(sys.argv) > 1: outfile = sys.argv[1] else: outfile = './obfuscator.hpp' if len(sys.argv) > 2: dirname = sys.argv[2] else: dirname = './obfuscator/obfs' merged = merge(dirname) write_hpp(outfile, merged) ================================================ FILE: script/string_obfs_tester.py ================================================ import sys def main(argc, argv): if argc < 3: print('USAGE: python string_obfs_tester.py [STRING_OBFS.EXE] [TARGET_STRING]') return 1 path = argv[1] with open(path, 'rb') as f: data = f.read() if data.find(str.encode(argv[2])) == -1: print('Cannot find string "{}" from "{}"'.format(argv[2], argv[1])) return 0 else: print('Find string "{}" from "{}"'.format(argv[2], argv[1])) return 1 if __name__ == '__main__': retn = main(len(sys.argv), sys.argv) sys.exit(retn) ================================================ FILE: test/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.10) project(unittest) set(CMAKE_CXX_STANDARD 17) file(GLOB test_files "impl/*.cpp" ) add_executable(unittest main.cpp ${test_files}) target_include_directories(unittest PRIVATE ../obfuscator) add_subdirectory(../external/Catch2 external) target_link_libraries(unittest Catch2::Catch2) ================================================ FILE: test/impl/fsm.cpp ================================================ #include #include #define STATE(Name) struct Name {}; #define EVENT(Name) struct Name {}; STATE(Final); EVENT(Trigger); STATE(state1); STATE(state2); STATE(state3); STATE(state4); STATE(state5); EVENT(event1); EVENT(event2); EVENT(event3); EVENT(event4); EVENT(event5); struct Action { static bool trigged; static void action() { trigged = true; } }; bool Action::trigged = true; struct Dummy { static int dummy; static void dummy1() { dummy += 10; } static void dummy2() { dummy *= 20; } }; int Dummy::dummy = 0; TEST_CASE("Next", "[obfs::StateMachine]") { using next = obfs::Next; static_assert(std::is_same_v); static_assert(std::is_same_v); static_assert(next::action == obfs::FreeAction); using next2 = obfs::Next; static_assert(next2::action == Action::action); } TEST_CASE("Stage", "[obfs::StateMachine]") { using stage = obfs::Stage< state1, obfs::Next, obfs::Next>; static_assert(std::is_same_v< obfs::Next, typename stage::template next>); static_assert(std::is_same_v< obfs::Next, typename obfs::next_stage::type>); static_assert(std::is_same_v< obfs::Next, typename stage::template next>); static_assert(std::is_same_v< obfs::Next, typename obfs::next_stage::type>); static_assert(std::is_same_v>); static_assert(std::is_same_v::type>); static_assert(std::is_same_v::type>); } TEST_CASE("StateMachine", "[obfs::StateMachine]") { using namespace obfs; using machine = StateMachine< Stage, Next>, Stage>, Stage>, Stage, Next>, Stage>>; auto failure = machine::run(obfs::None{}, event5{}); static_assert(std::is_same_v); auto next1 = machine::run(state1{}, event5{}); static_assert(std::is_same_v); REQUIRE(Dummy::dummy == 10); auto next2 = machine::run(next1, event2{}); static_assert(std::is_same_v); auto failure2 = machine::run(next2, event1{}); static_assert(std::is_same_v); auto next3 = machine::run(next2, event3{}); static_assert(std::is_same_v); REQUIRE(Dummy::dummy == 200); auto next4 = machine::run(next3, Trigger{}); static_assert(std::is_same_v); REQUIRE(Action::trigged); } ================================================ FILE: test/impl/random.cpp ================================================ #include #include using ull = unsigned long long; // https://en.wikipedia.org/wiki/Xorshift ull xorshift128plus(ull state[2]) { ull t = state[0]; ull const s = state[1]; state[0] = s; t ^= t << 23; // a t ^= t >> 17; // b t ^= s ^ (s >> 26); // c state[1] = t; return t + s; } TEST_CASE("Random case", "[obfs::Xorshift+]") { constexpr size_t val = MAKE_RAND_VAL(100); ull state[2] = { val, val << 1 }; REQUIRE(obfs::Xorshiftplus::value == xorshift128plus(state)); REQUIRE(obfs::Xorshiftplus::value == xorshift128plus(state)); REQUIRE(obfs::Xorshiftplus::value == xorshift128plus(state)); } ================================================ FILE: test/impl/sequence.cpp ================================================ #include #include TEST_CASE("TypeVal", "[obfs::Sequence]") { using val = obfs::TypeVal; static_assert(std::is_same_v); static_assert(val::value == 10); } TEST_CASE("Sequence", "[obfs::Sequence]") { using seq = obfs::Sequence; static_assert(std::is_same_v); static_assert(seq::size == 10); static_assert(seq::index<0>::value == 0); static_assert(seq::index<5>::value == 5); static_assert(seq::index<9>::value == 9); static_assert(std::is_same_v, obfs::Nothing>); } TEST_CASE("TypeSeq", "[obfs::Sequence]") { using namespace obfs; using seq = TypeSeq, TypeVal, TypeVal, TypeVal>; static_assert(seq::size == 4); static_assert(seq::index<0>::value == 0); static_assert(seq::index<2>::value == 2); static_assert(seq::index<3>::value == 3); static_assert(std::is_same_v, Nothing>); } TEST_CASE("MinVal", "[obfs::Sequence]") { using min = obfs::MinVal<1, 3, 2, 4, 9, 5, 6, 0, 7, 8>; static_assert(min::value == 0); } TEST_CASE("SeqPack", "[obfs::Sequence]") { using pack = obfs::SeqPack< obfs::Sequence, obfs::Sequence, obfs::Sequence >; static_assert(pack::size == 4); using item = pack::index<2>; static_assert(item::size == 3); static_assert(item::index<0>::value == 2); static_assert(item::index<1>::value == 3); static_assert(item::index<2>::value == 4); } template using condition = std::conditional_t<(Val::value > 3), Val, obfs::Pass>; template using first = typename obfs::First...>::type; TEST_CASE("First", "[obfs::Sequence]") { using result = first< obfs::TypeVal, obfs::TypeVal, obfs::TypeVal, obfs::TypeVal, obfs::TypeVal, obfs::TypeVal>; static_assert(result::value == 5); } ================================================ FILE: test/impl/string.cpp ================================================ #include #include template constexpr char enc_xor(char value) { return value ^ Key; } template constexpr char add(char c) { return c + Key; } template constexpr char comp(char c) { return f(g(c)); } TEST_CASE("Single encoder, decoder", "[obfs::String]") { REQUIRE( obfs::make_string, enc_xor<0x50>>("Hello World !").decode() == std::string_view("Hello World !")); } TEST_CASE("Multiple encoder, decoder", "[obfs::String]") { using table = obfs::make_table< obfs::encoder_seq, add<10>, comp, add<10>>>, obfs::decoder_seq, add<-10>, comp, enc_xor<0x50>>>>; MAKE_STRING(str, "Hello World !", table); REQUIRE(str.decode() == std::string_view("Hello World !")); } TEST_CASE("Multiple encoder, decoder pair", "[obfs::String]") { using table = obfs::make_pair_table< obfs::encoder_pair, enc_xor<0x50>>, obfs::encoder_pair, add<-10>>, obfs::encoder_pair, add<10>>, comp, enc_xor<0x50>>> >; MAKE_STRING(str, "Hello World !", table); REQUIRE(str.decode() == std::string_view("Hello World !")); } ================================================ FILE: test/main.cpp ================================================ #define CATCH_CONFIG_MAIN #include