JustasMasiulis/lazy_importer

library for importing functions from dlls in a hidden, reverse engineer unfriendly way

C++

1,928

80 commits

updated Aug 3, 2023

See the code

README

lazy importer

A simple and easy to use header only library to make the life of a reverse engineer much harder.

small example

LI_FN(OutputDebugStringA)("hello world");
LI_FN(VirtualProtect).in(LI_MODULE("kernel32.dll").cached());

IDA output when compiling first line

features

  • Does not leave any strings in memory.
  • Does not allocate any memory.
  • Can be easily inlined.
  • Does not leave any imports in the executable.
  • Produces extremely small assembly.
  • Non caching functions do not leave anything in data sections.
  • Hashes are randomized for each compilation to defeat basic hash database attacks.

documentation

  • LI_FN(function_pointer) -> lazy_function
  • LI_FN_DEF(function_type) -> lazy_function
  • LI_MODULE(module_name) -> lazy_module

  • safe indicates that when function cannot complete its task successfully 0 is returned instead of undefined behaviour manifesting.
  • cached indicates that the result is only computed during the first call and later reused.
  • forwarded indicates that export forwarding will be correctly resolved.

lazy_module

functionsafecached
Attempts to find the given module and returns its address
get<T = void*>() -> T❌❌
safe<T = void*>() -> T✅❌
cached<T = void*>() -> T❌✅
safe_cached<T = void*>() -> T✅✅
Attemps to find the given module using the given LDR_DATA_TABLE_ENTRY pointer
in<T = void*, Ldr>(Ldr ldr_entry) -> T✅❌
in_cached<T = void*, Ldr>(Ldr ldr_entry) -> T✅✅

lazy_function<F>

functionsafecachedforwarded
calls resolved export using given arguments
operator()(...) -> result_of<F, ...>❌❌❌
attempts to resolve an export in all loaded modules and returns the function address
get<T = F>() -> T❌❌❌
safe<T = F>() -> T✅❌❌
cached<T = F>() -> T❌✅❌
safe_cached<T = F>() -> T✅✅❌
forwarded<T = F>() -> T❌❌✅
forwarded_safe<T = F>() -> T✅❌✅
forwarded_cached<T = F>() -> T❌✅✅
forwarded_safe_cached<T = F>() -> T✅✅✅
attempts to resolve an export in the given module and returns the function address
in<T = F, A>(A module_address) -> T❌❌❌
in_safe<T = F, A>(A module_address) -> T✅❌❌
in_cached<T = F, A>(A module_address) -> T❌✅❌
in_safe_cached<T = F, A>(A module_address) -> T✅✅❌
attempts to resolve an export in ntdll and returns the function address
nt<T = F>() -> T❌❌❌
nt_safe<T = F>() -> T✅❌❌
nt_cached<T = F>() -> T❌✅❌
nt_safe_cached<T = F>() -> T✅✅❌

extra configuration

#defineeffects
LAZY_IMPORTER_NO_FORCEINLINEdisables force inlining
LAZY_IMPORTER_CASE_INSENSITIVEenables case insensitive comparison. Might be required for forwarded export resolution.
LAZY_IMPORTER_CACHE_OPERATOR_PARENSuses cached() instead of get() in operator() of lazy_function
LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTSuses forwarded() in get(). WARNING does not apply to nt() and in().
LAZY_IMPORTER_HARDENED_MODULE_CHECKSadds extra sanity checks to module enumeration.
LAZY_IMPORTER_NO_CPP_FORWARDRemoves dependence on <utility> c++ header.

example output

for ( i = *(_QWORD **)(*(_QWORD *)(__readgsqword(0x60u) + 24) + 16i64); ; i = (_QWORD *)*i )
  {
    v1 = i[6];
    v2 = *(unsigned int *)(*(signed int *)(v1 + 60) + v1 + 136);
    v3 = (_DWORD *)(v2 + v1);
    if ( v2 + v1 != v1 )
    {
      LODWORD(v4) = v3[6];
      if ( (_DWORD)v4 )
        break;
    }
LABEL_8:
    ;
  }
  while ( 1 )
  {
    v4 = (unsigned int)(v4 - 1);
    v5 = -2128831035;
    v6 = (char *)(v1 + *(unsigned int *)((unsigned int)v3[8] + 4 * v4 + v1));
    v7 = *v6;
    v8 = (signed __int64)(v6 + 1);
    if ( v7 )
    {
      do
      {
        ++v8;
        v5 = 16777619 * (v5 ^ v7);
        v7 = *(_BYTE *)(v8 - 1);
      }
      while ( v7 );
      if ( v5 == -973690651 )
        break;
    }
    if ( !(_DWORD)v4 )
      goto LABEL_8;
  }
  ((void (__fastcall *)(const char *))(v1
                                     + *(unsigned int *)(v1
                                                       + (unsigned int)v3[7]
                                                       + 4i64 * *(unsigned __int16 *)(v1 + (unsigned int)v3[9] + 2 * v4))))("hello world");

People that have supported this project

I would like to thank people that have reached out to me and donated some money to support me and my projects

anti-reversing
compile-time
cpp
export
game-hacking
getmodulehandle
getprocaddress
hashing
header-only
import
malware
obfuscation
reverse-engineering
small
static-analysis
windows

JustasMasiulis/lazy_importer

library for importing functions from dlls in a hidden, reverse engineer unfriendly way

C++

1,928

80 commits

updated Aug 3, 2023

See the code

README

lazy importer

A simple and easy to use header only library to make the life of a reverse engineer much harder.

small example

LI_FN(OutputDebugStringA)("hello world");
LI_FN(VirtualProtect).in(LI_MODULE("kernel32.dll").cached());

IDA output when compiling first line

features

  • Does not leave any strings in memory.
  • Does not allocate any memory.
  • Can be easily inlined.
  • Does not leave any imports in the executable.
  • Produces extremely small assembly.
  • Non caching functions do not leave anything in data sections.
  • Hashes are randomized for each compilation to defeat basic hash database attacks.

documentation

  • LI_FN(function_pointer) -> lazy_function
  • LI_FN_DEF(function_type) -> lazy_function
  • LI_MODULE(module_name) -> lazy_module

  • safe indicates that when function cannot complete its task successfully 0 is returned instead of undefined behaviour manifesting.
  • cached indicates that the result is only computed during the first call and later reused.
  • forwarded indicates that export forwarding will be correctly resolved.

lazy_module

functionsafecached
Attempts to find the given module and returns its address
get<T = void*>() -> T❌❌
safe<T = void*>() -> T✅❌
cached<T = void*>() -> T❌✅
safe_cached<T = void*>() -> T✅✅
Attemps to find the given module using the given LDR_DATA_TABLE_ENTRY pointer
in<T = void*, Ldr>(Ldr ldr_entry) -> T✅❌
in_cached<T = void*, Ldr>(Ldr ldr_entry) -> T✅✅

lazy_function<F>

functionsafecachedforwarded
calls resolved export using given arguments
operator()(...) -> result_of<F, ...>❌❌❌
attempts to resolve an export in all loaded modules and returns the function address
get<T = F>() -> T❌❌❌
safe<T = F>() -> T✅❌❌
cached<T = F>() -> T❌✅❌
safe_cached<T = F>() -> T✅✅❌
forwarded<T = F>() -> T❌❌✅
forwarded_safe<T = F>() -> T✅❌✅
forwarded_cached<T = F>() -> T❌✅✅
forwarded_safe_cached<T = F>() -> T✅✅✅
attempts to resolve an export in the given module and returns the function address
in<T = F, A>(A module_address) -> T❌❌❌
in_safe<T = F, A>(A module_address) -> T✅❌❌
in_cached<T = F, A>(A module_address) -> T❌✅❌
in_safe_cached<T = F, A>(A module_address) -> T✅✅❌
attempts to resolve an export in ntdll and returns the function address
nt<T = F>() -> T❌❌❌
nt_safe<T = F>() -> T✅❌❌
nt_cached<T = F>() -> T❌✅❌
nt_safe_cached<T = F>() -> T✅✅❌

extra configuration

#defineeffects
LAZY_IMPORTER_NO_FORCEINLINEdisables force inlining
LAZY_IMPORTER_CASE_INSENSITIVEenables case insensitive comparison. Might be required for forwarded export resolution.
LAZY_IMPORTER_CACHE_OPERATOR_PARENSuses cached() instead of get() in operator() of lazy_function
LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTSuses forwarded() in get(). WARNING does not apply to nt() and in().
LAZY_IMPORTER_HARDENED_MODULE_CHECKSadds extra sanity checks to module enumeration.
LAZY_IMPORTER_NO_CPP_FORWARDRemoves dependence on <utility> c++ header.

example output

for ( i = *(_QWORD **)(*(_QWORD *)(__readgsqword(0x60u) + 24) + 16i64); ; i = (_QWORD *)*i )
  {
    v1 = i[6];
    v2 = *(unsigned int *)(*(signed int *)(v1 + 60) + v1 + 136);
    v3 = (_DWORD *)(v2 + v1);
    if ( v2 + v1 != v1 )
    {
      LODWORD(v4) = v3[6];
      if ( (_DWORD)v4 )
        break;
    }
LABEL_8:
    ;
  }
  while ( 1 )
  {
    v4 = (unsigned int)(v4 - 1);
    v5 = -2128831035;
    v6 = (char *)(v1 + *(unsigned int *)((unsigned int)v3[8] + 4 * v4 + v1));
    v7 = *v6;
    v8 = (signed __int64)(v6 + 1);
    if ( v7 )
    {
      do
      {
        ++v8;
        v5 = 16777619 * (v5 ^ v7);
        v7 = *(_BYTE *)(v8 - 1);
      }
      while ( v7 );
      if ( v5 == -973690651 )
        break;
    }
    if ( !(_DWORD)v4 )
      goto LABEL_8;
  }
  ((void (__fastcall *)(const char *))(v1
                                     + *(unsigned int *)(v1
                                                       + (unsigned int)v3[7]
                                                       + 4i64 * *(unsigned __int16 *)(v1 + (unsigned int)v3[9] + 2 * v4))))("hello world");

People that have supported this project

I would like to thank people that have reached out to me and donated some money to support me and my projects

anti-reversing
compile-time
cpp
export
game-hacking
getmodulehandle
getprocaddress
hashing
header-only
import
malware
obfuscation
reverse-engineering
small
static-analysis
windows

Significant stargazers

patrick

239 followers · starred Nov 2020

Gijs de Jong

92 followers · starred May 2021

Cesar

75 followers · starred Jan 2025

Kelvin Zhang

35 followers · starred Jul 2020