Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
DInvoke — PInvoke 없이 관리 코드에서 임의의 비관리 코드를 동적으로 호출합니다. | Kitploit
도구/GitHubGitHub/thewover/dinvoke
Post-ExploitationRed TeamingPayload DevelopmentAdversarial Attack
GitHubthewover/dinvoke

DInvoke

PInvoke 없이 관리 코드에서 임의의 비관리 코드를 동적으로 호출합니다.

저장소 보기
79111263년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

DInvoke

Windows에서 PInvoke를 대체하는 동적 라이브러리입니다. DInvoke는 강력한 프리미티브를 포함하며, 이를 지능적으로 결합하여 디스크 또는 메모리에서 비관리 코드를 정밀하게 동적으로 호출할 수 있습니다. PE 파싱, 지능적인 동적 API 해석, 런타임 시 PE 플러그인 동적 로드, 프로세스 인젝션, API 후크 회피 등 다양한 목적으로 사용될 수 있습니다.

기능:

  • PInvoke 없이 비관리 API 동적 호출
  • 전략적 API 후크 회피를 가능하게 하는 프리미티브
  • 관리 코드에서 비관리 PE 모듈 수동 매핑
  • 디스크의 임의 모듈이 뒷받침하는 섹션에 PE 모듈 매핑
  • 모듈식 프로세스 인젝션 API
  • 데이터 구조, 델리게이트, 함수 래퍼로 구성된 성장 중인 라이브러리 (공유해 주세요 :-)
  • .NET v3.5+ 지원

컨퍼런스 발표 (Staying # & Bringing Covert Injection Tradecraft to .NET): https://www.youtube.com/watch?v=FuxpMXTgV9s

블로그 게시물:

  1. 은밀한 작전 에뮬레이션 - 동적 호출(PInvoke 및 API 후크 회피): https://thewover.github.io/Dynamic-Invoke/
  2. 곧 공개 예정.

이 프로젝트는 원래 SharpSploit (https://github.com/cobbr/SharpSploit)을 위해 만들어졌습니다. 작성자의 허락을 받아 현재는 독립 라이브러리이자 NuGet 패키지로 이곳에 호스팅됩니다. NuGet: https://www.nuget.org/packages/DInvoke/

예제 1 - 내보낸 비관리 API 확인

아래 예제는 DInvoke를 사용하여 DLL의 내보낸 함수를 동적으로 찾아 호출하는 방법을 보여줍니다.

  1. ntdll.dll의 기본 주소를 가져옵니다. ntdll.dll은 모든 Windows 프로세스가 초기화될 때 로드되므로 이미 로드되어 있을 것임을 알 수 있습니다. 따라서 PEB의 로드된 모듈 목록을 안전하게 검색하여 해당 참조를 찾을 수 있습니다. PEB에서 기본 주소를 찾으면 해당 주소를 출력합니다.
  2. GetLibraryAddress를 사용하여 이름으로 ntdll.dll 내의 내보낸 함수를 찾습니다.
  3. GetLibraryAddress를 사용하여 서수(ordinal)로 ntdll.dll 내의 내보낸 함수를 찾습니다.
  4. GetLibraryAddress를 사용하여 키 해시로 ntdll.dll 내의 내보낸 함수를 찾습니다.
  5. 앞서 찾은 ntdll.dll의 기본 주소가 주어지면 GetExportAddress를 사용하여 메모리의 모듈 내에서 이름으로 내보낸 함수를 찾습니다.
root@kitploit:~

///Author: b33f (@FuzzySec, Ruben Boonen)
using System;

using DynamicInvoke = DInvoke.DynamicInvoke;

namespace SpTestcase
{
    class Program
    {

        static void Main(string[] args)
        {
            // Details
            String testDetail = @"
            #=================>
            # Hello there!
            # I find things dynamically; base
            # addresses and function pointers.
            #=================>
            ";
            Console.WriteLine(testDetail);

            // Get NTDLL base from the PEB
            Console.WriteLine("[?] Resolve Ntdll base from the PEB..");
            IntPtr hNtdll = DynamicInvoke.Generic.GetPebLdrModuleEntry("ntdll.dll");
            Console.WriteLine("[>] Ntdll base address : " + string.Format("{0:X}", hNtdll.ToInt64()) + "\n");

            // Search function by name
            Console.WriteLine("[?] Specifying the name of a DLL (\"ntdll.dll\"), resolve a function by walking the export table in-memory..");
            Console.WriteLine("[+] Search by name --> NtCommitComplete");
            IntPtr pNtCommitComplete = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", "NtCommitComplete", true);
            Console.WriteLine("[>] pNtCommitComplete : " + string.Format("{0:X}", pNtCommitComplete.ToInt64()) + "\n");

            Console.WriteLine("[+] Search by ordinal --> 0x260 (NtSetSystemTime)");
            IntPtr pNtSetSystemTime = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", 0x260, true);
            Console.WriteLine("[>] pNtSetSystemTime : " + string.Format("{0:X}", pNtSetSystemTime.ToInt64()) + "\n");

            Console.WriteLine("[+] Search by keyed hash --> 138F2374EC295F225BD918F7D8058316 (RtlAdjustPrivilege)");
            Console.WriteLine("[>] Hash : HMACMD5(Key).ComputeHash(FunctionName)");
            String fHash = DynamicInvoke.Generic.GetAPIHash("RtlAdjustPrivilege", 0xaabb1122);
            IntPtr pRtlAdjustPrivilege = DynamicInvoke.Generic.GetLibraryAddress("ntdll.dll", fHash, 0xaabb1122);
            Console.WriteLine("[>] pRtlAdjustPrivilege : " + string.Format("{0:X}", pRtlAdjustPrivilege.ToInt64()) + "\n");

            // Search for function from base address of DLL
            Console.WriteLine("[?] Specifying the base address of DLL in memory ({0:X}), resolve function by walking its export table...", hNtdll.ToInt64());
            Console.WriteLine("[+] Search by name --> NtCommitComplete");
            IntPtr pNtCommitComplete2 = DynamicInvoke.Generic.GetExportAddress(hNtdll, "NtCommitComplete");
            Console.WriteLine("[>] pNtCommitComplete : " + string.Format("{0:X}", pNtCommitComplete2.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();
        }
    }
}

예제 2 - 비관리 코드 호출

아래 예제에서는 먼저 PInvoke를 사용하여 OpenProcess를 정상적으로 호출합니다. 그런 다음 DInvoke를 사용하여 여러 방식으로 호출하여 각 메커니즘이 비관리 코드를 성공적으로 실행하고 API 후크를 회피한다는 것을 보여줍니다.

root@kitploit:~

///Author: TheWover
using System;
using System.Runtime.InteropServices;

using Data = DInvoke.Data;
using DynamicInvoke = DInvoke.DynamicInvoke;
using ManualMap = DInvoke.ManualMap;

namespace SpTestcase
{
    class Program
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(
            Data.Win32.Kernel32.ProcessAccessFlags processAccess,
            bool bInheritHandle,
            uint processId
        );

        static void Main(string[] args)
        {
            // Details
            String testDetail = @"
            #=================>
            # Hello there!
            # I demonstrate API Hooking bypasses
            # by calling OpenProcess via
            # PInvoke then DInvoke.
            # All handles are requested with
            # PROCESS_ALL_ACCESS permissions.
            #=================>
            ";
            Console.WriteLine(testDetail);

            //PID of current process.
            uint id = Convert.ToUInt32(System.Diagnostics.Process.GetCurrentProcess().Id);

            //Process handle
            IntPtr hProc;

            // Create the array for the parameters for OpenProcess
            object[] paramaters =
            {
                Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS,
                false,
                id
            };

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Call OpenProcess using PInvoke
            Console.WriteLine("[?] Call OpenProcess via PInvoke ...");
            hProc = OpenProcess(Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, false, id);
            Console.WriteLine("[>] Process handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Call OpenProcess using GetLibraryAddress (underneath the hood)
            Console.WriteLine("[?] Call OpenProcess from the loaded module list using System.Diagnostics.Process.GetCurrentProcess().Modules ...");
            hProc = DynamicInvoke.Win32.OpenProcess(Data.Win32.Kernel32.ProcessAccessFlags.PROCESS_ALL_ACCESS, false, id);
            Console.WriteLine("[>] Process handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Search function by name from module in PEB
            Console.WriteLine("[?] Specifying the name of a DLL (\"kernel32.dll\"), search the PEB for the loaded module and resolve a function by walking the export table in-memory...");
            Console.WriteLine("[+] Search by name --> OpenProcess");
            IntPtr pkernel32 = DynamicInvoke.Generic.GetPebLdrModuleEntry("kernel32.dll");
            IntPtr pOpenProcess = DynamicInvoke.Generic.GetExportAddress(pkernel32, "OpenProcess");

            //Call OpenProcess
            hProc = (IntPtr)DynamicInvoke.Generic.DynamicFunctionInvoke(pOpenProcess, typeof(DynamicInvoke.Win32.Delegates.OpenProcess), ref paramaters);
            Console.WriteLine("[>] Process Handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Manually map kernel32.dll
            // Search function by name from module in PEB
            Console.WriteLine("[?] Manually map a fresh copy of a DLL (\"kernel32.dll\"), and resolve a function by walking the export table in-memory...");
            Console.WriteLine("[+] Search by name --> OpenProcess");
            Data.PE.PE_MANUAL_MAP moduleDetails = ManualMap.Map.MapModuleToMemory("C:\\Windows\\System32\\kernel32.dll");
            Console.WriteLine("[>] Module Base : " + string.Format("{0:X}", moduleDetails.ModuleBase.ToInt64()) + "\n");

            //Call OpenProcess
            hProc = (IntPtr)DynamicInvoke.Generic.CallMappedDLLModuleExport(moduleDetails.PEINFO, moduleDetails.ModuleBase, "OpenProcess", typeof(DynamicInvoke.Win32.Delegates.OpenProcess), paramaters);
            Console.WriteLine("[>] Process Handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            // Map kernel32.dll using Module Overloading
            // Search function by name from module in PEB
            Console.WriteLine("[?] Use Module Overloading to map a fresh copy of a DLL (\"kernel32.dll\") into memory backed by another file on disk. Resolve a function by walking the export table in-memory...");
            Console.WriteLine("[+] Search by name --> OpenProcess");
            moduleDetails = ManualMap.Overload.OverloadModule("C:\\Windows\\System32\\kernel32.dll");
            Console.WriteLine("[>] Module Base : " + string.Format("{0:X}", moduleDetails.ModuleBase.ToInt64()) + "\n");

            //Call OpenProcess
            hProc = (IntPtr)DynamicInvoke.Generic.CallMappedDLLModuleExport(moduleDetails.PEINFO, moduleDetails.ModuleBase, "OpenProcess", typeof(DynamicInvoke.Win32.Delegates.OpenProcess), paramaters);
            Console.WriteLine("[>] Process Handle : " + string.Format("{0:X}", hProc.ToInt64()) + "\n");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            Console.WriteLine("[!] Test complete!");

            // Pause execution
            Console.WriteLine("[*] Pausing execution..");
            Console.ReadLine();

        }
    }
}


이것이 후크를 회피했는지 테스트하기 위해 API Monitor v2 도구를 사용하여 kernel32.dll!OpenProcess를 후킹하겠습니다. 그런 다음 API Monitor를 통해 데모를 실행합니다. PROCESS_ALL_ACCESS 플래그와 함께 호출되는 항목을 관찰하면 OpenProcess 호출 중 어떤 것이 후크에 걸렸는지 알 수 있습니다. 보시다시피 API Monitor는 PInvoke로 수행된 API 호출을 성공적으로 포착합니다. 그러나 DInvoke 또는 Manual Mapping을 사용할 때는 포착하지 못합니다. 실제 동작은 Vimeo에서 동영상으로 확인할 수 있습니다.

SharpSploit: DInvoke 및 Manual Mapping을 통한 API 후크 우회

크레딧

  • The Wover
  • FuzzySec (b33f)
  • cobbr
도구 다운로드