commit 88a02618809b0dc6a608886b7300a00880e6f1d2 Author: HorizonCode Date: Thu Sep 29 12:31:39 2022 +0200 initial push diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b4020e3 --- /dev/null +++ b/.clang-format @@ -0,0 +1,17 @@ +IndentWidth: 4 +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +UseTab: Never +ColumnLimit: 0 +SpaceAfterCStyleCast: true +PointerAlignment: Right +NamespaceIndentation: All +AlwaysBreakTemplateDeclarations: Yes +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: None +AllowShortLoopsOnASingleLine: false +IndentPPDirectives: AfterHash diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..01981a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vs +.temp + +build \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2a4d8f1 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# osu-auth-reader +Read portions of the raw token from osu's anticheat. + +That's all really! + +![Demo Image](https://i.imgur.com/pmTf8Y0.png) diff --git a/ac_checker.sln b/ac_checker.sln new file mode 100644 index 0000000..9f6797f --- /dev/null +++ b/ac_checker.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32505.173 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ac_checker", "ac_checker\ac_checker.vcxproj", "{4FA0ACF4-DC50-4201-82BD-3A11664286AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4FA0ACF4-DC50-4201-82BD-3A11664286AC}.Debug|x86.ActiveCfg = Debug|Win32 + {4FA0ACF4-DC50-4201-82BD-3A11664286AC}.Debug|x86.Build.0 = Debug|Win32 + {4FA0ACF4-DC50-4201-82BD-3A11664286AC}.Release|x86.ActiveCfg = Release|Win32 + {4FA0ACF4-DC50-4201-82BD-3A11664286AC}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {43EE6F3D-E5C7-4D8E-868F-4EF339262E61} + EndGlobalSection +EndGlobal diff --git a/ac_checker/ac_checker.vcxproj b/ac_checker/ac_checker.vcxproj new file mode 100644 index 0000000..ee20067 --- /dev/null +++ b/ac_checker/ac_checker.vcxproj @@ -0,0 +1,103 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + 16.0 + Win32Proj + {4fa0acf4-dc50-4201-82bd-3a11664286ac} + acchecker + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + $(SolutionDir)\build\$(Configuration)\ + $(SolutionDir)\.temp\$(Configuration)\ + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)\include; + + + $(SolutionDir)\build\$(Configuration)\ + $(SolutionDir)\.temp\$(Configuration)\ + $(VC_IncludePath);$(WindowsSDK_IncludePath);$(ProjectDir)\include; + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpplatest + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ac_checker/ac_checker.vcxproj.filters b/ac_checker/ac_checker.vcxproj.filters new file mode 100644 index 0000000..e57222e --- /dev/null +++ b/ac_checker/ac_checker.vcxproj.filters @@ -0,0 +1,51 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/ac_checker/ac_checker.vcxproj.user b/ac_checker/ac_checker.vcxproj.user new file mode 100644 index 0000000..966b4ff --- /dev/null +++ b/ac_checker/ac_checker.vcxproj.user @@ -0,0 +1,6 @@ + + + + true + + \ No newline at end of file diff --git a/ac_checker/include/util/hooklib.hpp b/ac_checker/include/util/hooklib.hpp new file mode 100644 index 0000000..ae78571 --- /dev/null +++ b/ac_checker/include/util/hooklib.hpp @@ -0,0 +1,31 @@ +#pragma once +#include +#include + +namespace util { + + struct Hook { + uintptr_t _bytes = 0; + uintptr_t _target = 0; + uintptr_t _detour = 0; + uintptr_t _tramp = 0; + + bool enable(uintptr_t target, uintptr_t detour); + void disable(); + + template + inline bool enable(Target target, Detour detour) { + return enable((uintptr_t) target, (uintptr_t) detour); + } + + template + inline auto invoke(Args &&...args) const { + return ((Func) _tramp)(std::forward(args)...); + } + }; + +} // namespace util + +#define define_hook(name, ret, call_conv, ...) \ + inline util::Hook name; \ + ret call_conv name##_hook(__VA_ARGS__); \ No newline at end of file diff --git a/ac_checker/include/util/memory.hpp b/ac_checker/include/util/memory.hpp new file mode 100644 index 0000000..f5a3798 --- /dev/null +++ b/ac_checker/include/util/memory.hpp @@ -0,0 +1,16 @@ +#pragma once +#include +#include + +namespace signatures { + + constexpr static auto s_token_log_ref = "558BEC83EC08C645FC01C745"; + +} + +namespace util { + + uint8_t *find_pattern(std::string_view pattern, uint8_t *begin, size_t size, ptrdiff_t offset = 0x0); + uint8_t *scan_module(std::string_view module_name, std::string_view pattern, ptrdiff_t offset = 0x0); + +} // namespace util \ No newline at end of file diff --git a/ac_checker/include/util/pe.hpp b/ac_checker/include/util/pe.hpp new file mode 100644 index 0000000..80b7fcb --- /dev/null +++ b/ac_checker/include/util/pe.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +// <3 mr polish man + +namespace util { + + struct ModuleInfo { + uintptr_t base; + size_t size; + }; + + ModuleInfo get_module(std::string_view module_name); + uintptr_t get_export(std::string_view module_name, std::string_view export_name); + +} // namespace util \ No newline at end of file diff --git a/ac_checker/include/vendor/hde.hpp b/ac_checker/include/vendor/hde.hpp new file mode 100644 index 0000000..61b68a2 --- /dev/null +++ b/ac_checker/include/vendor/hde.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include + +#define C_NONE 0x00 +#define C_MODRM 0x01 +#define C_IMM8 0x02 +#define C_IMM16 0x04 +#define C_IMM_P66 0x10 +#define C_REL8 0x20 +#define C_REL32 0x40 +#define C_GROUP 0x80 +#define C_ERROR 0xff + +#define PRE_ANY 0x00 +#define PRE_NONE 0x01 +#define PRE_F2 0x02 +#define PRE_F3 0x04 +#define PRE_66 0x08 +#define PRE_67 0x10 +#define PRE_LOCK 0x20 +#define PRE_SEG 0x40 +#define PRE_ALL 0xff + +#define DELTA_OPCODES 0x4a +#define DELTA_FPU_REG 0xf1 +#define DELTA_FPU_MODRM 0xf8 +#define DELTA_PREFIXES 0x130 +#define DELTA_OP_LOCK_OK 0x1a1 +#define DELTA_OP2_LOCK_OK 0x1b9 +#define DELTA_OP_ONLY_MEM 0x1cb +#define DELTA_OP2_ONLY_MEM 0x1da + +#define F_MODRM 0x00000001 +#define F_SIB 0x00000002 +#define F_IMM8 0x00000004 +#define F_IMM16 0x00000008 +#define F_IMM32 0x00000010 +#define F_DISP8 0x00000020 +#define F_DISP16 0x00000040 +#define F_DISP32 0x00000080 +#define F_RELATIVE 0x00000100 +#define F_2IMM16 0x00000800 +#define F_ERROR 0x00001000 +#define F_ERROR_OPCODE 0x00002000 +#define F_ERROR_LENGTH 0x00004000 +#define F_ERROR_LOCK 0x00008000 +#define F_ERROR_OPERAND 0x00010000 +#define F_PREFIX_REPNZ 0x01000000 +#define F_PREFIX_REPX 0x02000000 +#define F_PREFIX_REP 0x03000000 +#define F_PREFIX_66 0x04000000 +#define F_PREFIX_67 0x08000000 +#define F_PREFIX_LOCK 0x10000000 +#define F_PREFIX_SEG 0x20000000 +#define F_PREFIX_ANY 0x3f000000 + +#define PREFIX_SEGMENT_CS 0x2e +#define PREFIX_SEGMENT_SS 0x36 +#define PREFIX_SEGMENT_DS 0x3e +#define PREFIX_SEGMENT_ES 0x26 +#define PREFIX_SEGMENT_FS 0x64 +#define PREFIX_SEGMENT_GS 0x65 +#define PREFIX_LOCK 0xf0 +#define PREFIX_REPNZ 0xf2 +#define PREFIX_REPX 0xf3 +#define PREFIX_OPERAND_SIZE 0x66 +#define PREFIX_ADDRESS_SIZE 0x67 + +#pragma pack(push, 1) + +typedef struct { + uint8_t len; + uint8_t p_rep; + uint8_t p_lock; + uint8_t p_seg; + uint8_t p_66; + uint8_t p_67; + uint8_t opcode; + uint8_t opcode2; + uint8_t modrm; + uint8_t modrm_mod; + uint8_t modrm_reg; + uint8_t modrm_rm; + uint8_t sib; + uint8_t sib_scale; + uint8_t sib_index; + uint8_t sib_base; + union { + uint8_t imm8; + uint16_t imm16; + uint32_t imm32; + } imm; + union { + uint8_t disp8; + uint16_t disp16; + uint32_t disp32; + } disp; + uint32_t flags; +} hde32s; + +#pragma pack(pop) + +unsigned int hde32_disasm(const void *code, hde32s *hs); diff --git a/ac_checker/include/vendor/small_vector.hpp b/ac_checker/include/vendor/small_vector.hpp new file mode 100644 index 0000000..d5f805a --- /dev/null +++ b/ac_checker/include/vendor/small_vector.hpp @@ -0,0 +1,371 @@ +#pragma once +#include +#include +#include + +namespace vendor { + + template > + class small_vector { + std::array stack_; + std::vector heap_; + std::size_t size_{0}; + + public: + typedef T value_type; + typedef std::size_t size_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef Allocator allocator_type; + typedef T *pointer; + typedef const T *const_pointer; + + small_vector() = default; + + explicit small_vector(size_type count, const T &value = T(), const Allocator &alloc = Allocator()) { + if (count == N) { + stack_.fill(value); + } else if (count < N) { + for (size_t i = 0; i < count; i++) { + stack_[i] = value; + } + } else { + // use heap + heap_ = std::move(std::vector(count, value, alloc)); + } + size_ = count; + } + + small_vector(const small_vector &other, const Allocator &alloc = Allocator()) + : stack_(other.stack_), heap_(other.heap_, alloc), size_(other.size_) { + } + + small_vector(small_vector &&other, const Allocator &alloc = Allocator()) + : stack_(std::move(other.stack_)), heap_(std::move(other.heap_), alloc), size_(std::move(other.size_)) { + } + + small_vector(std::initializer_list initlist, const Allocator &alloc = Allocator()) { + const auto input_size = initlist.size(); + if (input_size <= N) { + std::copy(initlist.begin(), initlist.end(), stack_.begin()); + } else { + heap_ = std::move(std::vector(initlist, alloc)); + } + size_ = input_size; + } + + small_vector &operator=(const small_vector &rhs) { + stack_ = rhs.stack_; + heap_ = rhs.heap_; + size_ = rhs.size_; + return *this; + } + + small_vector &operator=(small_vector &&rhs) { + stack_ = std::move(rhs.stack_); + heap_ = std::move(rhs.heap_); + size_ = rhs.size_; + rhs.size_ = 0; + return *this; + } + + small_vector &operator=(std::initializer_list rhs) { + if (rhs.size() <= N) { + stack_ = rhs; + } else { + heap_ = rhs; + } + size_ = rhs.size(); + } + + allocator_type get_allocator() const noexcept { + return heap_.get_allocator(); + } + + reference at(size_type pos) { + if (size_ < N) { + return stack_.at(pos); + } else { + return heap_.at(pos); + } + } + + const_reference at(size_type pos) const { + if (size_ < N) { + return stack_.at(pos); + } else { + return heap_.at(pos); + } + } + + reference operator[](size_type pos) { + if (size_ < N) { + return stack_[pos]; + } else { + return heap_[pos]; + } + } + + const_reference operator[](size_type pos) const { + if (size_ < N) { + return stack_[pos]; + } else { + return heap_[pos]; + } + } + + reference front() { + if (size_ < N) { + return stack_.front(); + } else { + return heap_.front(); + } + } + + const_reference front() const { + if (size_ < N) { + return stack_.front(); + } else { + return heap_.front(); + } + } + + reference back() { + if (size_ < N) { + return stack_[size_ - 1]; + } else { + return heap_[size_ - 1]; + } + } + + const_reference back() const { + if (size_ < N) { + return stack_[size_ - 1]; + } else { + return heap_[size_ - 1]; + } + } + + pointer data() noexcept { + if (size_ < N) { + return stack_.data(); + } else { + return heap_.data(); + } + } + + const_pointer data() const noexcept { + if (size_ < N) { + return stack_.data(); + } else { + return heap_.data(); + } + } + + bool empty() const { + return size_ == 0; + } + + size_type size() const { + return size_; + } + + void shrink_to_fit() { + if (size_ >= N) { + heap_.shrink_to_fit(); + } + } + + void push_back(const T &value) { + if (size_ < N) { + stack_[size_] = value; + } else { + if (size_ == N) { + // move everything to heap + std::move(stack_.begin(), stack_.end(), std::back_inserter(heap_)); + } + heap_.push_back(value); + } + size_ += 1; + } + + void push_back(T &&value) { + if (size_ < N) { + stack_[size_] = std::move(value); + } else { + if (size_ == N) { + // move everything to heap + std::move(stack_.begin(), stack_.end(), std::back_inserter(heap_)); + } + heap_.push_back(std::move(value)); + } + size_ += 1; + } + + void pop_back() { + if (size_ == 0) { + // do nothing + return; + } + + if (size_ < N) { + size_ -= 1; + } else { + // currently using heap + heap_.pop_back(); + size_ -= 1; + + // now check if all data can fit on stack + // if so, move back to stack + if (size_ < N) { + std::move(heap_.begin(), heap_.end(), stack_.begin()); + heap_.clear(); + } + } + } + + // Resizes the container to contain count elements. + void resize(size_type count, T value = T()) { + if (count <= N) { + // new `count` of elements completely fit on stack + if (size_ >= N) { + // currently, all data on heap + // move back to stack + std::move(heap_.begin(), heap_.end(), stack_.begin()); + } else { + // all data already on stack + // just update size + } + } else { + // new `count` of data is going to be on the heap + // check if data is currently on the stack + if (size_ < N) { + // move to heap + std::move(stack_.begin(), stack_.end(), std::back_inserter(heap_)); + } + heap_.resize(count, value); + } + size_ = count; + } + + void swap(small_vector &other) noexcept { + std::swap(stack_, other.stack_); + std::swap(heap_, other.heap_); + std::swap(size_, other.size_); + }; + + // Assigns the given value value to all elements in the container + void fill(const_reference value) { + if (size_ < N) { + stack_.fill(value); + } else { + std::fill(heap_.begin(), heap_.end(), value); + } + } + + class iterator { + pointer ptr_; + + public: + typedef iterator self_type; + typedef T value_type; + typedef T &reference; + typedef T *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef int difference_type; + iterator(pointer ptr) + : ptr_(ptr) { + } + self_type operator++() { + ptr_++; + return *this; + } + self_type operator++(int) { + self_type i = *this; + ptr_++; + return i; + } + reference operator*() { + return *ptr_; + } + pointer operator->() { + return ptr_; + } + bool operator==(const self_type &rhs) { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type &rhs) { + return ptr_ != rhs.ptr_; + } + }; + + class const_iterator { + pointer ptr_; + + public: + typedef const_iterator self_type; + typedef T value_type; + typedef T &reference; + typedef T *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + const_iterator(pointer ptr) + : ptr_(ptr) { + } + self_type operator++() { + ptr_++; + return *this; + } + self_type operator++(int) { + self_type i = *this; + ptr_++; + return i; + } + const value_type &operator*() { + return *ptr_; + } + const pointer operator->() { + return ptr_; + } + bool operator==(const self_type &rhs) { + return ptr_ == rhs.ptr_; + } + bool operator!=(const self_type &rhs) { + return ptr_ != rhs.ptr_; + } + }; + + iterator begin() { + if (size_ < N) { + return iterator(stack_.data()); + } else { + return iterator(heap_.data()); + } + } + + iterator end() { + if (size_ < N) { + return iterator(stack_.data() + size_); + } else { + return iterator(heap_.data() + size_); + } + } + + const_iterator begin() const { + if (size_ < N) { + return const_iterator(stack_.data()); + } else { + return const_iterator(heap_.data()); + } + } + + const_iterator end() const { + if (size_ < N) { + return const_iterator(stack_.data() + size_); + } else { + return const_iterator(heap_.data() + size_); + } + } + }; + +} // namespace vendor diff --git a/ac_checker/main.cpp b/ac_checker/main.cpp new file mode 100644 index 0000000..3163c8c --- /dev/null +++ b/ac_checker/main.cpp @@ -0,0 +1,49 @@ +#include +#include +#include +#include + +#include +#include + +define_hook(log_token, int, __fastcall, uintptr_t, uintptr_t, char *, size_t); + +template +constexpr auto x86_abs_addr(T source, ptrdiff_t disp, size_t length) { + return (uintptr_t) (source + disp + length); +} + +static int __fastcall log_token_hook(uintptr_t ecx, uintptr_t edx, char *text, size_t size) { + if (size == 4 /*A trash value representing a flag has been pushed; do not print it.*/) { + fprintf(stdout, "[!] flag detected!\n"); + } else { + fprintf(stdout, "[~] %s\n", text); + } + + return log_token.invoke(ecx, edx, text, size); +} + +bool __stdcall DllMain(uintptr_t instance, uint32_t reason, uintptr_t reserved) { + if (reason == 1) { + std::thread([]() { + AllocConsole(); + SetConsoleTitleA("1337 h4x0r ac checker"); + freopen_s((FILE **) stdout, "CONOUT$", "w", stdout); + + fprintf(stdout, "iroha // pushfq\n"); + + if (auto addr = util::scan_module("osu!auth.dll", signatures::s_token_log_ref, 0x1A)) { + log_token.enable(x86_abs_addr(addr, *(ptrdiff_t *) (addr + 0x1), 0x5), log_token_hook); + } + // The user is likely using a targeted build. (TODO: perhaps add support for this where possible?) + else { + MessageBoxA(nullptr, "Unsupported target.", "osu!", MB_OK | MB_TOPMOST); + exit(0); + } + + fprintf(stdout, "initialized.\n"); + }).detach(); + } + + return true; +} \ No newline at end of file diff --git a/ac_checker/source/util/hooklib.cpp b/ac_checker/source/util/hooklib.cpp new file mode 100644 index 0000000..a9b83d0 --- /dev/null +++ b/ac_checker/source/util/hooklib.cpp @@ -0,0 +1,76 @@ +#include +#include +#include + +namespace util { + + constexpr uint8_t target_shellcode[] = { + 0x8D, 0x64, 0x24, 0xFC, // lea esp, [esp-0x4] + 0xC7, 0x04, 0x24, 0xFF, 0xFF, 0xFF, 0xFF, // mov DWORD PTR [esp], ADDRESS + 0xC3 // ret + }; + + constexpr uint8_t tramp_shellcode[] = { + 0x68, 0xFF, 0xFF, 0xFF, 0xFF, // push imm32 + 0xC3, // ret + }; + + bool Hook::enable(uintptr_t target, uintptr_t detour) { + hde32s hde_state; + + while (_bytes < sizeof(target_shellcode)) { + _bytes += hde32_disasm((const void *) (target + _bytes), &hde_state); + + if (hde_state.opcode == 0xC3) { + _bytes = 0; + return false; + } + } + + auto tramp = VirtualAlloc(nullptr, _bytes + sizeof(tramp_shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + if (!tramp) { + _bytes = 0; + return false; + } + + unsigned long old_prot; + + VirtualProtect((void *) target, _bytes, PAGE_EXECUTE_READWRITE, &old_prot); + + _target = target; + _detour = detour; + _tramp = (uintptr_t) tramp; + + memcpy((uint8_t *) _tramp, (const uint8_t *) _target, _bytes); + memcpy((uint8_t *) _tramp + _bytes, tramp_shellcode, sizeof(tramp_shellcode)); + memcpy((uint8_t *) _target, target_shellcode, sizeof(target_shellcode)); + + *(uintptr_t *) (_target + 7) = _detour; + *(uintptr_t *) (_tramp + _bytes + 1) = _target + _bytes; + + VirtualProtect((void *) target, _bytes, old_prot, &old_prot); + + return true; + } + + void Hook::disable() { + if (!_bytes) + return; + + unsigned long old_prot; + + VirtualProtect((void *) _target, _bytes, PAGE_EXECUTE_READWRITE, &old_prot); + + memcpy((uint8_t *) _target, (const uint8_t *) _tramp + _bytes, _bytes); + + VirtualFree((void *) _tramp, 0, MEM_RELEASE); + VirtualProtect((void *) _target, _bytes, old_prot, &old_prot); + + _bytes = 0; + _target = 0; + _detour = 0; + _tramp = 0; + } + +} // namespace util \ No newline at end of file diff --git a/ac_checker/source/util/memory.cpp b/ac_checker/source/util/memory.cpp new file mode 100644 index 0000000..d91b508 --- /dev/null +++ b/ac_checker/source/util/memory.cpp @@ -0,0 +1,64 @@ +#include +#include +#include + +namespace util { + + constexpr uint8_t hex_to_byte(char ch) { + if (ch >= '0' && ch <= '9') { + return ch - '0'; + } else if (ch >= 'a' && ch <= 'f') { + return ch - 'a' + 10; + } else if (ch >= 'A' && ch <= 'F') { + return ch - 'A' + 10; + } + + // >.< + std::unreachable(); + } + + constexpr uint8_t stich_byte(char x, char y) { + return hex_to_byte(x) << 4 | hex_to_byte(y); + } + + uint8_t *find_pattern(std::string_view pattern, uint8_t *begin, size_t size, ptrdiff_t offset) { + vendor::small_vector vec; + + for (auto i = 0u; i < pattern.size(); i++) { + auto &ch = pattern[i]; + + if (ch == '?') { + vec.push_back(0xCC); + } else if (std::isxdigit(ch)) { + vec.push_back(stich_byte(ch, pattern[++i])); + } + } + + for (auto mem = begin; mem < begin + size; mem++) { + bool is_found = true; + + for (auto i = 0u; i < vec.size(); i++) { + if (vec[i] != 0xCC && vec[i] != mem[i]) { + is_found = false; + break; + } + } + + if (is_found) { + return mem + offset; + } + } + + return nullptr; + } + + uint8_t *scan_module(std::string_view module_name, std::string_view pattern, ptrdiff_t offset) { + auto module_info = util::get_module(module_name); + + if (!module_info.base) + return nullptr; + + return util::find_pattern(pattern, (uint8_t *) module_info.base, module_info.size, offset); + } + +} // namespace util \ No newline at end of file diff --git a/ac_checker/source/util/pe.cpp b/ac_checker/source/util/pe.cpp new file mode 100644 index 0000000..12eb480 --- /dev/null +++ b/ac_checker/source/util/pe.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include + +struct LdrEntry { + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderLinks; + LIST_ENTRY InInitializationOrderLinks; + uintptr_t DllBase; + uintptr_t EntryPoint; + uint32_t SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; +}; + +namespace util { + + ModuleInfo get_module(std::string_view module_name) { + auto peb = ((_TEB *) __readfsdword(0x18))->ProcessEnvironmentBlock; + auto list = &peb->Ldr->InMemoryOrderModuleList; + + size_t wide_name_length = 0; + wchar_t wide_name[256] = {0}; + + mbstowcs_s(&wide_name_length, wide_name, 256, module_name.data(), module_name.size()); + + for (auto iter = list->Flink; iter != list; iter = iter->Flink) { + auto entry = CONTAINING_RECORD(iter, LdrEntry, InMemoryOrderLinks); + + if (entry->BaseDllName.Buffer && _wcsnicmp(entry->BaseDllName.Buffer, wide_name, wide_name_length) == 0) { + return { + .base = entry->DllBase, + .size = entry->SizeOfImage, + }; + } + } + + return {}; + } + + uintptr_t get_export(std::string_view module_name, std::string_view export_name) { + auto module_info = get_module(module_name); + auto module_base = module_info.base; + + if (!module_base) + return 0u; + + auto dos_hdr = (IMAGE_DOS_HEADER *) module_base; + auto nt_hdrs = (IMAGE_NT_HEADERS *) (module_base + dos_hdr->e_lfanew); + + auto exports_va = nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + auto exports_size = nt_hdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; + auto exports = (IMAGE_EXPORT_DIRECTORY *) (module_base + exports_va); + + auto names = (uintptr_t *) (module_base + exports->AddressOfNames); + auto functions = (uintptr_t *) (module_base + exports->AddressOfFunctions); + auto name_ordinals = (uint16_t *) (module_base + exports->AddressOfNameOrdinals); + + for (auto i = 0u; i < exports->NumberOfNames; i++) { + if (export_name.compare((const char *) (module_base + names[i])) == 0) + return module_base + functions[name_ordinals[i]]; + } + + return 0u; + } + +} // namespace util \ No newline at end of file diff --git a/ac_checker/source/vendor/hde.cpp b/ac_checker/source/vendor/hde.cpp new file mode 100644 index 0000000..299b215 --- /dev/null +++ b/ac_checker/source/vendor/hde.cpp @@ -0,0 +1,340 @@ +#include +#include + +static unsigned char hde32_table[] = { + 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xa3, 0xa8, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xac, 0xaa, 0xb2, 0xaa, 0x9f, 0x9f, 0x9f, 0x9f, 0xb5, 0xa3, 0xa3, 0xa4, 0xaa, 0xaa, 0xba, 0xaa, 0x96, 0xaa, 0xa8, 0xaa, + 0xc3, 0xc3, 0x96, 0x96, 0xb7, 0xae, 0xd6, 0xbd, 0xa3, 0xc5, 0xa3, 0xa3, 0x9f, 0xc3, 0x9c, 0xaa, 0xaa, 0xac, 0xaa, 0xbf, 0x03, 0x7f, + 0x11, 0x7f, 0x01, 0x7f, 0x01, 0x3f, 0x01, 0x01, 0x90, 0x82, 0x7d, 0x97, 0x59, 0x59, 0x59, 0x59, 0x59, 0x7f, 0x59, 0x59, 0x60, 0x7d, + 0x7f, 0x7f, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x9a, 0x88, 0x7d, 0x59, 0x50, 0x50, 0x50, 0x50, + 0x59, 0x59, 0x59, 0x59, 0x61, 0x94, 0x61, 0x9e, 0x59, 0x59, 0x85, 0x59, 0x92, 0xa3, 0x60, 0x60, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, + 0x59, 0x59, 0x59, 0x59, 0x59, 0x9f, 0x01, 0x03, 0x01, 0x04, 0x03, 0xd5, 0x03, 0xcc, 0x01, 0xbc, 0x03, 0xf0, 0x10, 0x10, 0x10, 0x10, + 0x50, 0x50, 0x50, 0x50, 0x14, 0x20, 0x20, 0x20, 0x20, 0x01, 0x01, 0x01, 0x01, 0xc4, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0xc0, 0xc2, 0x10, 0x11, 0x02, 0x03, 0x11, 0x03, 0x03, 0x04, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x00, 0xc6, 0xc8, 0x02, 0x02, 0x02, + 0x02, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xca, 0x01, 0x01, 0x01, 0x00, 0x06, 0x00, 0x04, 0x00, 0xc0, 0xc2, + 0x01, 0x01, 0x03, 0x01, 0xff, 0xff, 0x01, 0x00, 0x03, 0xc4, 0xc4, 0xc6, 0x03, 0x01, 0x01, 0x01, 0xff, 0x03, 0x03, 0x03, 0xc8, 0x40, + 0x00, 0x0a, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xbf, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4b, 0x52, 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4c, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x55, 0x45, 0x40, 0x4a, 0x4a, 0x4a, + 0x45, 0x59, 0x4d, 0x46, 0x4a, 0x5d, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x61, 0x63, + 0x67, 0x4e, 0x4a, 0x4a, 0x6b, 0x6d, 0x4a, 0x4a, 0x45, 0x6d, 0x4a, 0x4a, 0x44, 0x45, 0x4a, 0x4a, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x06, + 0x06, 0x06, 0x06, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x02, 0x06, 0x00, 0x0a, 0x0a, 0x07, 0x07, 0x06, + 0x02, 0x05, 0x05, 0x02, 0x02, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x0e, 0x05, 0x06, 0x06, 0x06, 0x01, 0x06, 0x00, + 0x00, 0x08, 0x00, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x28, 0x00, 0x30, 0x00, 0x80, 0x01, 0x82, 0x01, 0x86, 0x00, 0xf6, 0xcf, 0xfe, + 0x3f, 0xab, 0x00, 0xb0, 0x00, 0xb1, 0x00, 0xb3, 0x00, 0xba, 0xf8, 0xbb, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc7, 0xbf, 0x62, 0xff, 0x00, + 0x8d, 0xff, 0x00, 0xc4, 0xff, 0x00, 0xc5, 0xff, 0x00, 0xff, 0xff, 0xeb, 0x01, 0xff, 0x0e, 0x12, 0x08, 0x00, 0x13, 0x09, 0x00, 0x16, + 0x08, 0x00, 0x17, 0x09, 0x00, 0x2b, 0x09, 0x00, 0xae, 0xff, 0x07, 0xb2, 0xff, 0x00, 0xb4, 0xff, 0x00, 0xb5, 0xff, 0x00, 0xc3, 0x01, + 0x00, 0xc7, 0xff, 0xbf, 0xe7, 0x08, 0x00, 0xf0, 0x02, 0x00 // +}; + +unsigned int hde32_disasm(const void *code, hde32s *hs) { + uint8_t x, c, *p = (uint8_t *) code, cflags, opcode, pref = 0; + uint8_t *ht = hde32_table, m_mod, m_reg, m_rm, disp_size = 0; + + memset(hs, 0, sizeof(hde32s)); + + for (x = 16; x; x--) + switch (c = *p++) { + case 0xf3: + hs->p_rep = c; + pref |= PRE_F3; + break; + case 0xf2: + hs->p_rep = c; + pref |= PRE_F2; + break; + case 0xf0: + hs->p_lock = c; + pref |= PRE_LOCK; + break; + case 0x26: + case 0x2e: + case 0x36: + case 0x3e: + case 0x64: + case 0x65: + hs->p_seg = c; + pref |= PRE_SEG; + break; + case 0x66: + hs->p_66 = c; + pref |= PRE_66; + break; + case 0x67: + hs->p_67 = c; + pref |= PRE_67; + break; + default: goto pref_done; + } +pref_done: + + hs->flags = (uint32_t) pref << 23; + + if (!pref) + pref |= PRE_NONE; + + if ((hs->opcode = c) == 0x0f) { + hs->opcode2 = c = *p++; + ht += DELTA_OPCODES; + } else if (c >= 0xa0 && c <= 0xa3) { + if (pref & PRE_67) + pref |= PRE_66; + else + pref &= ~PRE_66; + } + + opcode = c; + cflags = ht[ht[opcode / 4] + (opcode % 4)]; + + if (cflags == C_ERROR) { + hs->flags |= F_ERROR | F_ERROR_OPCODE; + cflags = 0; + if ((opcode & -3) == 0x24) + cflags++; + } + + x = 0; + if (cflags & C_GROUP) { + uint16_t t; + t = *(uint16_t *) (ht + (cflags & 0x7f)); + cflags = (uint8_t) t; + x = (uint8_t) (t >> 8); + } + + if (hs->opcode2) { + ht = hde32_table + DELTA_PREFIXES; + if (ht[ht[opcode / 4] + (opcode % 4)] & pref) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (cflags & C_MODRM) { + hs->flags |= F_MODRM; + hs->modrm = c = *p++; + hs->modrm_mod = m_mod = c >> 6; + hs->modrm_rm = m_rm = c & 7; + hs->modrm_reg = m_reg = (c & 0x3f) >> 3; + + if (x && ((x << m_reg) & 0x80)) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + + if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) { + uint8_t t = opcode - 0xd9; + if (m_mod == 3) { + ht = hde32_table + DELTA_FPU_MODRM + t * 8; + t = ht[m_reg] << m_rm; + } else { + ht = hde32_table + DELTA_FPU_REG; + t = ht[t] << m_reg; + } + if (t & 0x80) + hs->flags |= F_ERROR | F_ERROR_OPCODE; + } + + if (pref & PRE_LOCK) { + if (m_mod == 3) { + hs->flags |= F_ERROR | F_ERROR_LOCK; + } else { + uint8_t *table_end, op = opcode; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_LOCK_OK; + table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK; + } else { + ht = hde32_table + DELTA_OP_LOCK_OK; + table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK; + op &= -2; + } + for (; ht != table_end; ht++) + if (*ht++ == op) { + if (!((*ht << m_reg) & 0x80)) + goto no_lock_error; + else + break; + } + hs->flags |= F_ERROR | F_ERROR_LOCK; + no_lock_error:; + } + } + + if (hs->opcode2) { + switch (opcode) { + case 0x20: + case 0x22: + m_mod = 3; + if (m_reg > 4 || m_reg == 1) + goto error_operand; + else + goto no_error_operand; + case 0x21: + case 0x23: + m_mod = 3; + if (m_reg == 4 || m_reg == 5) + goto error_operand; + else + goto no_error_operand; + } + } else { + switch (opcode) { + case 0x8c: + if (m_reg > 5) + goto error_operand; + else + goto no_error_operand; + case 0x8e: + if (m_reg == 1 || m_reg > 5) + goto error_operand; + else + goto no_error_operand; + } + } + + if (m_mod == 3) { + uint8_t *table_end; + if (hs->opcode2) { + ht = hde32_table + DELTA_OP2_ONLY_MEM; + table_end = ht + sizeof(hde32_table) - DELTA_OP2_ONLY_MEM; + } else { + ht = hde32_table + DELTA_OP_ONLY_MEM; + table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM; + } + for (; ht != table_end; ht += 2) + if (*ht++ == opcode) { + if ((*ht++ & pref) && !((*ht << m_reg) & 0x80)) + goto error_operand; + else + break; + } + goto no_error_operand; + } else if (hs->opcode2) { + switch (opcode) { + case 0x50: + case 0xd7: + case 0xf7: + if (pref & (PRE_NONE | PRE_66)) + goto error_operand; + break; + case 0xd6: + if (pref & (PRE_F2 | PRE_F3)) + goto error_operand; + break; + case 0xc5: goto error_operand; + } + goto no_error_operand; + } else + goto no_error_operand; + + error_operand: + hs->flags |= F_ERROR | F_ERROR_OPERAND; + no_error_operand: + + c = *p++; + if (m_reg <= 1) { + if (opcode == 0xf6) + cflags |= C_IMM8; + else if (opcode == 0xf7) + cflags |= C_IMM_P66; + } + + switch (m_mod) { + case 0: + if (pref & PRE_67) { + if (m_rm == 6) + disp_size = 2; + } else if (m_rm == 5) + disp_size = 4; + break; + case 1: disp_size = 1; break; + case 2: + disp_size = 2; + if (!(pref & PRE_67)) + disp_size <<= 1; + break; + } + + if (m_mod != 3 && m_rm == 4 && !(pref & PRE_67)) { + hs->flags |= F_SIB; + p++; + hs->sib = c; + hs->sib_scale = c >> 6; + hs->sib_index = (c & 0x3f) >> 3; + if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1)) + disp_size = 4; + } + + p--; + switch (disp_size) { + case 1: + hs->flags |= F_DISP8; + hs->disp.disp8 = *p; + break; + case 2: + hs->flags |= F_DISP16; + hs->disp.disp16 = *(uint16_t *) p; + break; + case 4: + hs->flags |= F_DISP32; + hs->disp.disp32 = *(uint32_t *) p; + break; + } + p += disp_size; + } else if (pref & PRE_LOCK) + hs->flags |= F_ERROR | F_ERROR_LOCK; + + if (cflags & C_IMM_P66) { + if (cflags & C_REL32) { + if (pref & PRE_66) { + hs->flags |= F_IMM16 | F_RELATIVE; + hs->imm.imm16 = *(uint16_t *) p; + p += 2; + goto disasm_done; + } + goto rel32_ok; + } + if (pref & PRE_66) { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *) p; + p += 2; + } else { + hs->flags |= F_IMM32; + hs->imm.imm32 = *(uint32_t *) p; + p += 4; + } + } + + if (cflags & C_IMM16) { + if (hs->flags & F_IMM32) { + hs->flags |= F_IMM16; + hs->disp.disp16 = *(uint16_t *) p; + } else if (hs->flags & F_IMM16) { + hs->flags |= F_2IMM16; + hs->disp.disp16 = *(uint16_t *) p; + } else { + hs->flags |= F_IMM16; + hs->imm.imm16 = *(uint16_t *) p; + } + p += 2; + } + if (cflags & C_IMM8) { + hs->flags |= F_IMM8; + hs->imm.imm8 = *p++; + } + + if (cflags & C_REL32) { + rel32_ok: + hs->flags |= F_IMM32 | F_RELATIVE; + hs->imm.imm32 = *(uint32_t *) p; + p += 4; + } else if (cflags & C_REL8) { + hs->flags |= F_IMM8 | F_RELATIVE; + hs->imm.imm8 = *p++; + } + +disasm_done: + + if ((hs->len = (uint8_t) (p - (uint8_t *) code)) > 15) { + hs->flags |= F_ERROR | F_ERROR_LENGTH; + hs->len = 15; + } + + return (unsigned int) hs->len; +}