📄 tcpip_patcher.c
字号:
IoStatus->Information = OutputBufferLength;
break;
case IOCTL_PATCHER_SET_LIMIT:
/* supplied buffer must be big enough to contain our response */
if ((OutputBufferLength < sizeof (PATCHER_LIMIT_DATA)) ||
(OutputBuffer == NULL))
{
PATCHER_DBG(("Wrong output buffer size for IOCTL_PATCHER_SET_LIMIT\n"));
IoStatus->Status = STATUS_INVALID_BUFFER_SIZE;
break;
}
/* supplied input buffer must contain our parameter struct */
if ((InputBufferLength < sizeof (PATCHER_LIMIT_DATA)) ||
(InputBuffer == NULL))
{
PATCHER_DBG(("Wrong input buffer size for IOCTL_PATCHER_SET_LIMIT\n"));
IoStatus->Status = STATUS_INVALID_BUFFER_SIZE;
break;
}
/* Get new limit requested by caller */
LimitData = (PATCHER_LIMIT_DATA*) InputBuffer;
RequestedLimit = LimitData->HalfOpenLimit;
/* Prepare our result data */
LimitData = (PATCHER_LIMIT_DATA*) OutputBuffer;
LimitData->HalfOpenLimit = 0;
LimitData->CurrentHalfOpen = 0;
LimitData->ErrorCode = PATCHER_ERROR_FAILURE;
LogData.Buffer = LimitData->LogString;
LogData.Remaining = OutputBufferLength - sizeof(PATCHER_LIMIT_DATA);
if (LogData.Remaining > 0)
LogData.Buffer[0] = 0;
/* Do some sanity checking on the requested limit */
if (RequestedLimit < 10 || RequestedLimit > 16384)
{
PATCHER_LOG_0("Requested half open limit out of range (10,16384)\n");
LimitData->ErrorCode = PATCHER_ERROR_FAILURE;
IoStatus->Information = OutputBufferLength;
break;
}
__try
{
PVOID TcpIpBase, DataStart, DataEnd;
ULONG CodeSecRVA, CodeSecSize;
ULONG DataSecRVA, DataSecSize;
ULONG *LimitAddress, *CurrentHalfOpenAddress;
TcpIpBase = FindModuleBase ("tcpip.sys", &LogData);
if (TcpIpBase != NULL)
{
if (FindPESections (TcpIpBase, &CodeSecRVA, &CodeSecSize,
&DataSecRVA, &DataSecSize, &LogData))
{
LimitAddress = FindLimitPosition (((PCHAR)TcpIpBase) + CodeSecRVA,
CodeSecSize,
&CurrentHalfOpenAddress,
&LogData);
if (LimitAddress != NULL && CurrentHalfOpenAddress != NULL)
{
/* addresses must be in data section */
DataStart = ((PCHAR)TcpIpBase) + DataSecRVA;
DataEnd = ((PCHAR)DataStart) + DataSecSize;
if ((PVOID)LimitAddress > DataStart &&
(PVOID)LimitAddress < DataEnd &&
(PVOID)CurrentHalfOpenAddress > DataStart &&
(PVOID)CurrentHalfOpenAddress < DataEnd)
{
/* set new limit */
*LimitAddress = RequestedLimit;
/* return requested data */
LimitData->HalfOpenLimit = *LimitAddress;
LimitData->CurrentHalfOpen = *CurrentHalfOpenAddress;
LimitData->ErrorCode = PATCHER_ERROR_SUCCESS;
PATCHER_LOG_1("Successfully set half open connections limit to %d\n",
LimitData->HalfOpenLimit);
}
else
{
PATCHER_LOG_0("Address of limit or current half open not in data section\n");
}
}
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
PATCHER_LOG_0("Caught exception during IOCTL_PATCHER_SET_LIMIT\n");
LimitData->ErrorCode = PATCHER_ERROR_FAILURE;
}
/* Make the IOManager copy everything */
IoStatus->Information = OutputBufferLength;
break;
default:
PATCHER_DBG(("Invalid PatcherDeviceControl parameter\n"));
IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
return IoStatus->Status;
}
/*****************************************************************************/
/* The code patterns we look for to determine the address of the half-open
* limit variable we need to patch. */
ULONG CodePos1CurrentOff = 11;
ULONG CodePos1LimitOff = 17;
BYTE CodePos1Data[] = "\x3D\x02\x00\xC0\xE9\x8E\x29\xFE\xFF\x56\xA1\x20\xFE\x04\x00\x3B\x05\x1C\xFE\x04\x00\x7D\x51\x8B\x45\xF8\xFF\x45\xF8\x83\xF8\x14\x73\x46";
BYTE CodePos1Mask[] = "\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
/* ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ */
/* some jump offset current halfopen halfopen limit */
ULONG CodePos2CurrentOff = 12;
ULONG CodePos2LimitOff = 18;
BYTE CodePos2Data[] = "\x8B\xCB\x88\x45\x0B\xFF\x15\x28\xEF\x04\x00\xA1\x20\xFE\x04\x00\x3B\x05\x1C\xFE\x04\x00\x0F\x8D\x07\x10\x02\x00\x33\xF6";
BYTE CodePos2Mask[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x00\xFF\xFF";
/* ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ */
/* KefAcquireSpinLockAtDpcLevel current halfopen halfopen limit some jump offset */
ULONG CodePos3CurrentOff = 3;
BYTE CodePos3Data[] = "\x33\xC9\xB8\x20\xFE\x04\x00\x41\xF0\x0F\xC1\x08\xA1\x28\xFE\x04\x00\x33\xC9\x8D\x04\x85\xA0\x3C\x05\x00\x41\xF0\x0F\xC1\x08\xC3";
BYTE CodePos3Mask[] = "\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF";
/* ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ */
/* current halfopen some offset some offset */
/* Returns address of DWORD containing half-open connections limit and
* optionally address of current half-open connections */
ULONG* FindLimitPosition (PVOID CodeStart, ULONG CodeSize,
ULONG **CurrentHalfOpenAddress, LOG_DATA *pLogData)
{
PCHAR Pos1, Pos2, Pos3;
/* find all three code snippets */
Pos1 = FindMemWithMask (CodeStart, CodeSize, CodePos1Data, CodePos1Mask,
sizeof (CodePos1Data));
if(Pos1 == NULL)
{
PATCHER_LOG_0("Code snippet 1 not found\n");
return NULL;
}
PATCHER_LOG_1("Code snippet 1 found at %p\n", Pos1);
PATCHER_LOG_2("Current half-open address: %p, Limit address: %p\n",
*((ULONG*)(Pos1 + CodePos1CurrentOff)),
*((ULONG*)(Pos1 + CodePos1LimitOff)));
Pos2 = FindMemWithMask (CodeStart, CodeSize, CodePos2Data, CodePos2Mask,
sizeof (CodePos2Data));
if(Pos2 == NULL)
{
PATCHER_LOG_0("Code snippet 2 not found\n");
return NULL;
}
PATCHER_LOG_1("Code snippet 2 found at %p\n", Pos2);
PATCHER_LOG_2("Current half-open address: %p, Limit address: %p\n",
*((ULONG*)(Pos2 + CodePos2CurrentOff)),
*((ULONG*)(Pos2 + CodePos2LimitOff)));
Pos3 = FindMemWithMask (CodeStart, CodeSize, CodePos3Data, CodePos3Mask,
sizeof (CodePos3Data));
if(Pos3 == NULL)
{
PATCHER_LOG_0("Code snippet 3 not found\n");
return NULL;
}
PATCHER_LOG_1("Code snippet 3 found at %p\n", Pos3);
PATCHER_LOG_1("Current half-open address: %p\n",
*((ULONG*)(Pos3 + CodePos3CurrentOff)));
/* compare current half-open addresses */
if (*((ULONG*)(Pos1 + CodePos1CurrentOff)) != *((ULONG*)(Pos2 + CodePos2CurrentOff)))
{
PATCHER_LOG_0("Addresses for current half-open don't match between snippet 1 and 2!\n");
return NULL;
}
if (*((ULONG*)(Pos2 + CodePos2CurrentOff)) != *((ULONG*)(Pos3 + CodePos3CurrentOff)))
{
PATCHER_LOG_0("Addresses for current half-open don't match between snippet 2 and 3!\n");
return NULL;
}
PATCHER_LOG_1("Current half-open connections: %u\n",
**((ULONG**)(Pos1 + CodePos1CurrentOff)));
/* compare limit addresses */
if (*((ULONG*)(Pos1 + CodePos1LimitOff)) != *((ULONG*)(Pos2 + CodePos2LimitOff)))
{
PATCHER_LOG_0("Addresses for half-open limit don't match between snippet 1 and 2!\n");
return NULL;
}
PATCHER_LOG_1("Current half-open limit: %u\n",
**((ULONG**)(Pos1 + CodePos1LimitOff)));
/* return addresses */
if (CurrentHalfOpenAddress != NULL)
*CurrentHalfOpenAddress = (ULONG*) *((ULONG*)(Pos1 + CodePos1CurrentOff));
return (ULONG*) *((ULONG*)(Pos1 + CodePos1LimitOff));
}
/*****************************************************************************/
/* Returns base address of module (e.g. "tcpip.sys") */
PVOID FindModuleBase (const char *module, LOG_DATA *pLogData)
{
SYSTEM_MODULE_INFORMATION *mods;
NTSTATUS status;
PCHAR buf = NULL;
ULONG buf_size = 48*1024;
ULONG len, i;
if (module == NULL)
return NULL;
PATCHER_LOG_1("Looking for module '%s'\n", module);
do
{
if((buf = (PCHAR)ExAllocatePool(NonPagedPool,buf_size)) == NULL)
return NULL;
status = ZwQuerySystemInformation(SystemModuleInformation,buf,
buf_size,NULL);
if(status == STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePool (buf);
buf_size *= 2;
if (buf_size > 512*1024)
{
PATCHER_LOG_0("Module buffer size exceeds 512 KB, aborting search.\n");
return NULL;
}
}
else if (!NT_SUCCESS(status))
{
ExFreePool (buf);
PATCHER_LOG_1("ZwQuerySystemInformation failed with %X\n",
status);
return NULL;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
len = *((ULONG *)buf);
mods = (SYSTEM_MODULE_INFORMATION *)(buf + sizeof (ULONG));
PATCHER_LOG_1("Retrieved %d modules\n", len);
for(i = 0; i < len; i++)
{
if (_stricmp(mods[i].ImageName + mods[i].ModuleNameOffset, module) == 0)
{
PVOID Base = mods[i].Base;
PATCHER_LOG_2("Found module '%s' at %p\n", module, Base);
ExFreePool (buf);
return Base;
}
}
PATCHER_LOG_1("Module '%s' not found in memory\n", module);
ExFreePool (buf);
return NULL;
}
/* Returns RVA and size of code and data sections */
BOOL FindPESections (PVOID ImageBase,
ULONG *CodeRVA, ULONG *CodeSize,
ULONG *DataRVA, ULONG *DataSize,
LOG_DATA *pLogData)
{
PCHAR Base = (PCHAR)ImageBase;
PIMAGE_DOS_HEADER DOSHdr;
PIMAGE_NT_HEADERS32 NTHdr;
PIMAGE_FILE_HEADER FileHdr;
PIMAGE_OPTIONAL_HEADER32 OptHdr;
PIMAGE_SECTION_HEADER SecHdr, CodeSecHdr = NULL, DataSecHdr = NULL;
int i;
if (Base == NULL)
return FALSE;
DOSHdr = (PIMAGE_DOS_HEADER)Base;
if (DOSHdr->e_magic != 0x5A4D)
{
PATCHER_LOG_0("DOS header not found\n");
return FALSE;
}
NTHdr = (PIMAGE_NT_HEADERS32) (Base + DOSHdr->e_lfanew);
if (NTHdr->Signature != 0x00004550)
{
PATCHER_LOG_0("PE signature not found\n");
return FALSE;
}
FileHdr = &NTHdr->FileHeader;
if (FileHdr->Machine != 0x014C)
{
PATCHER_LOG_0("Not a i386 PE file\n");
return FALSE;
}
if (FileHdr->SizeOfOptionalHeader != 0xE0)
{
PATCHER_LOG_0("Size of optional header is not 0xE0\n");
return FALSE;
}
OptHdr = &NTHdr->OptionalHeader;
if (OptHdr->Magic != 0x010B) /* 0x010B is 32bit executable image */
{
PATCHER_LOG_0("Wrong optional header magic\n");
return FALSE;
}
if (OptHdr->NumberOfRvaAndSizes != 0x010)
{
PATCHER_LOG_0("NumberOfRvaAndSizes not 16\n");
return FALSE;
}
SecHdr = (PIMAGE_SECTION_HEADER)(((PCHAR)OptHdr) +
sizeof(IMAGE_OPTIONAL_HEADER32));
/* find .text and .data sections */
for (i = 0; i < FileHdr->NumberOfSections; i++)
{
#if 0
char buf[9];
memcpy(buf, SecHdr[i].Name, 8);
buf[8] = 0;
PATCHER_LOG_1("Section: %s\n", buf);
#endif
if (memcmp(SecHdr[i].Name, ".text\x00\x00\x00", 8) == 0)
CodeSecHdr = SecHdr + i;
if (memcmp(SecHdr[i].Name, ".data\x00\x00\x00", 8) == 0)
DataSecHdr = SecHdr + i;
}
if (CodeSecHdr == NULL)
{
PATCHER_LOG_0(".text section not found in image\n");
return FALSE;
}
if (DataSecHdr == NULL)
{
PATCHER_LOG_0(".data section not found in image\n");
return FALSE;
}
if ((CodeSecHdr->Characteristics & 0x20) == 0) /* IMAGE_SCN_CNT_CODE */
{
PATCHER_LOG_0(".text section does not contain code\n");
return FALSE;
}
if ((DataSecHdr->Characteristics & 0x20) != 0) /* IMAGE_SCN_CNT_CODE */
{
PATCHER_LOG_0(".data section contains code\n");
return FALSE;
}
PATCHER_LOG_2("Code section found at RVA 0x%08X size 0x%08X\n",
CodeSecHdr->VirtualAddress, CodeSecHdr->Misc.VirtualSize);
if (CodeRVA != NULL)
*CodeRVA = CodeSecHdr->VirtualAddress;
if (CodeSize != NULL)
*CodeSize = CodeSecHdr->Misc.VirtualSize;
PATCHER_LOG_2("Data section found at RVA 0x%08X size 0x%08X\n",
DataSecHdr->VirtualAddress, DataSecHdr->Misc.VirtualSize);
if (DataRVA != NULL)
*DataRVA = DataSecHdr->VirtualAddress;
if (DataSize != NULL)
*DataSize = DataSecHdr->Misc.VirtualSize;
return TRUE;
}
/* Find needle with mask. */
PVOID FindMemWithMask (const PVOID Start, ULONG Size, const PCHAR NeedleData,
const PCHAR NeedleMask, ULONG NeedleSize)
{
ULONG FirstData, FirstMask;
PCHAR Haystack = Start;
ULONG Left, i;
if (!Start || !NeedleData || !NeedleMask || Size < NeedleSize ||
NeedleSize < sizeof (ULONG))
{
return NULL;
}
FirstMask = ((ULONG*)NeedleMask)[0];
FirstData = ((ULONG*)NeedleData)[0] & FirstMask;
Left = Size - NeedleSize;
while (Left > 0)
{
/* quickly find potential position (hopefully first long isn't common) */
while ((*((ULONG*)Haystack) & FirstMask) != FirstData)
{
Haystack++;
Left--;
if (Left == 0)
return NULL;
}
#if 0
PATCHER_DBG(("Potential match found at %p\n", Haystack));
#endif
/* compare entire needle */
for (i = 0; i < NeedleSize; i++)
{
if ((Haystack[i] & NeedleMask[i]) != (NeedleData[i] & NeedleMask[i]))
break;
}
if (i == NeedleSize)
return Haystack;
Haystack++;
Left--;
}
return NULL;
}
/*****************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -