-
Автор темы
- #1
Всем ку, держите неплохой спуф калл с подменой калл стека, он намного лучше и безопаснее баянистого спуфа от
P.s. ASM код всратый, можно переписать/оптимизировать.
Пожалуйста, авторизуйтесь для просмотра ссылки.
, не использует баянистый jmp rbx/rcx/rdi/etc гаджет и содержит ROP цепочку из фейк вызовов находящихся в сигнед модулях, также на данный момент гаджет не проверяется в BE/EAC P.s. ASM код всратый, можно переписать/оптимизировать.
C++:
// 48 83 C4 C3
add rsp, 0xX
ret
C++:
EXTERNDEF proxy_call_returns:QWORD
EXTERNDEF proxy_call_fakestack:QWORD
EXTERNDEF proxy_call_fakestack_size:QWORD
.DATA
proxy_call_returns QWORD 32 dup (?)
proxy_call_fakestack dq ?
proxy_call_fakestack_size dq ?
.CODE
proxy_call_stub PROC PUBLIC
; push arguments
push 0 ; stack align
push r9 ; save 4th arg
push r8 ; save 3th arg
push rdx ; save 2th arg
push rcx ; save 1th arg
mov rax, rdx ; mov function address to rax
mov rcx, rsp ; mov stack value to rcx
add rcx, 50h ; adjust stack
mov rdx, rcx ; store stack to compare later
; check for arguments length
cmp qword ptr[rsp], 21376969 ; check if it's last argument (our fake argument)
jz end_args_calc ; we found our fake argument
mov rax, r8; ; new possible function address
cmp qword ptr[rsp + 8], 21376969h ; check if it's last argument (our fake argument)
jz end_args_calc ; we found our fake argument
mov rax, r9; ; new possible function address
cmp r8, 21376969h ; check if it's last argument (our fake argument)
jz end_args_calc ; we found our fake argument
mov rax, [rcx] ; new possible function address
cmp r9, 21376969h ; check if it's last argument (our fake argument)
jz end_args_calc ; we found our fake argument
; stackwalk to found our fake argument
check_for_args_end:
mov rax, [rcx + 8] ; new possible function address
cmp qword ptr[rcx], 21376969h ; check if it's last argument (our fake argument)
jz end_args_calc ; we found our fake argument
add rcx, 8 ; add stack argument
jmp check_for_args_end
end_args_calc:
sub rcx, rdx ; stack arguments size in bytes
mov r8, cleanup_call
push r8 ; push our cleanup return address
; create fake callstack
mov r10, rcx
mov rcx, proxy_call_fakestack_size
cmp rcx, 0
jz skip_fakecallstack
lea r8, [rcx * 8]
sub rsp, r8
; backup register
mov r8, rsi
mov r9, rdi
mov rsi, proxy_call_fakestack
mov rdi, rsp
rep movsq
; restore registers
mov rsi, r8
mov rdi, r9
skip_fakecallstack:
mov rcx, r10
; stack align
mov r8, rcx
and r8, 15
mov r8, rcx
jnz stack_aligned
push 0
add r8, 8
stack_aligned:
; build callstack
push_value:
cmp rcx, 0
jz do_call
push [rdx + rcx - 8]
sub rcx, 8
jmp push_value
do_call:
add r8, 20h
; psuedo sub rsp, 20h
push 0
push 0
push 0
push 0
; push proper return address
lea r9, proxy_call_returns
mov r9, [r9 + r8]
push r9
mov r9, [rdx - 38h] ; restore original r9
mov r8, [rdx - 40h] ; restore original r8
mov rcx, [rdx - 50h] ; restore original rcx
mov rdx, [rdx - 48h] ; restore original rdx
xor r12, r12
xor r14, r14
jmp rax ; call function
cleanup_call:
add rsp, 28h
ret
proxy_call_stub ENDP
END
C++:
#pragma once
#include <windows.h>
#include <cstdint>
#include <map>
#include <vector>
namespace safe_utils
{
extern "C" void proxy_call_stub();
extern "C" std::uintptr_t proxy_call_returns[];
extern "C" std::size_t proxy_call_fakestack_size;
extern "C" std::uintptr_t * proxy_call_fakestack;
template <typename return_type, typename... Args> __forceinline auto spoof_call(uintptr_t procedure, Args... args)
{
return reinterpret_cast<return_type(__cdecl*)(Args..., std::uint64_t, void*)>(proxy_call_stub)(Args(args)..., 0x21376969, reinterpret_cast<void*>(procedure));
}
__forceinline void* __cdecl safe_memset(void* dest, int value, size_t num)
{
__stosb(static_cast<unsigned char*>(dest),
static_cast<unsigned char>(value), num);
return dest;
}
__forceinline void* __cdecl safe_memcpy(void* dest, const void* src, size_t num)
{
__movsb(static_cast<unsigned char*>(dest),
static_cast<const unsigned char*>(src), num);
return dest;
}
void prepare_proxy_for_module(std::uint8_t* module, std::uint32_t max_fakestack = 12)
{
std::map<std::int8_t, std::vector<std::uintptr_t>> proxy_clean_returns;
auto dos = reinterpret_cast<IMAGE_DOS_HEADER*>(module);
auto nt = reinterpret_cast<IMAGE_NT_HEADERS*>(module + dos->e_lfanew);
auto image_size = nt->OptionalHeader.SizeOfImage;
auto section = IMAGE_FIRST_SECTION(nt);
MEMORY_BASIC_INFORMATION mbi;
for (auto i = 0; i < nt->FileHeader.NumberOfSections; i++)
{
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
{
auto address = module + section->VirtualAddress;
while (true)
{
safe_memset(&mbi, 0, sizeof(mbi));
if (!VirtualQuery(address, &mbi, sizeof(mbi)))
break;
auto base_page = (std::uint8_t*) mbi.BaseAddress;
if (mbi.Protect == PAGE_EXECUTE_READ ||
mbi.Protect == PAGE_EXECUTE_READWRITE ||
mbi.Protect == PAGE_EXECUTE_WRITECOPY)
{
for (auto i = 0u; i < (mbi.RegionSize - 0x10); i++)
{
// add rsp, 0xX
// ret
if (base_page[i] == 0x48 &&
base_page[i + 1] == 0x83 &&
base_page[i + 2] == 0xC4 &&
base_page[i + 4] == 0xC3)
{
proxy_clean_returns[base_page[i + 3]].push_back(std::uintptr_t(base_page + i));
}
}
}
address = base_page + mbi.RegionSize;
if (address >= (module + section->VirtualAddress + section->Misc.VirtualSize))
break;
}
}
section++;
}
std::vector<std::int8_t> proxy_clean_returns_keys;
proxy_clean_returns_keys.reserve(proxy_clean_returns.size());
std::vector<std::uintptr_t> fakestack;
fakestack.reserve(max_fakestack * 2);
for (auto& it : proxy_clean_returns)
{
const auto index = (it.first / sizeof(std::uintptr_t));
proxy_call_returns[index] = it.second.at(__rdtsc() % it.second.size());
if (index < 10 && index % 2 == 1) //for stack align
proxy_clean_returns_keys.push_back(it.first);
}
while (fakestack.size() < max_fakestack)
{
const auto pseudo_random_number = __rdtsc();
const auto return_length = proxy_clean_returns_keys.at(pseudo_random_number % proxy_clean_returns_keys.size());
const auto params = (return_length / sizeof(std::uintptr_t));
const auto& address_array = proxy_clean_returns[return_length];
const auto random_address = address_array.at(pseudo_random_number % address_array.size());
fakestack.push_back(random_address);
for (auto i = 0u; i < params; i++)
fakestack.push_back(std::uintptr_t(module) + (__rdtsc() % image_size));
}
proxy_call_fakestack_size = fakestack.size();
proxy_call_fakestack = new std::uintptr_t[fakestack.size()];
safe_memcpy(proxy_call_fakestack, fakestack.data(), proxy_call_fakestack_size * sizeof(std::uintptr_t));
}
}
C++:
auto kernel32_base = GetModuleHandleA("kernel32.dll");
auto beep_func = reinterpret_cast<uintptr_t>(GetProcAddress(kernel32_base, "Beep"));
constexpr int32_t fake_stack_size = 12;
safe_utils::prepare_proxy_for_module(reinterpret_cast<uint8_t*>(kernel32_base), fake_stack_size);
DWORD dwFreq = 1000;
DWORD dwDuration = 100;
using tBeep = decltype(&Beep);
safe_utils::spoof_call<tBeep>(beep_func, dwFreq, dwDuration);
Последнее редактирование: