魔兽争霸 3 踢人内挂

作者:

在

话说 war3 会自动把 war3.exe 所在目录下的 .mix 文件作为 DLL 加载~~

所以编译成 DLL 改成 xxx.mix 放在 war3.exe 的目录里面就好了~~

Update at 0:23 2012/10/28: 我忽然发现我几乎把所有的错误处理都忽略掉了。大概是太久没写代码了。

//
// 默认调用约定:__stdcall
//
// WAR3 数据包格式来源于 W3GStreamer。
//

#include
#include

#define ORDINAL_SEND (0x00000013)

#define ENTRY_NOT_FOUND (-1)

#define PACKET_SIGNATURE (0xF7)
#define PACKET_CHAT (0x0F)

#define PACKET_CHAT_FLAG_IN_PREPARE_SCREEN (0x10)
#define PACKET_CHAT_FLAG_IN_GAME (0x20)

#define COMMAND_KICK "/kick"

#define Add2Ptr(Pointer, Increment, ResultType) (reinterpret_cast((ULONG_PTR)(Pointer) + (Increment)))
#define PtrOffset(Pointer2, Pointer1) ((reinterpret_cast(Pointer2) - reinterpret_cast(Pointer1)))

typedef DWORD (SEND) (
__in SOCKET Socket,
__in_bcount(BufferSize) PVOID Buffer,
__in DWORD BufferSize,
__in DWORD Flags
);

typedef SEND *PSEND;

typedef __declspec(align(1)) struct _GAME_PACKET {
BYTE Signature;
BYTE Operation;
WORD PacketSize;

union {
struct {
BYTE TargetCount;

//
// 接下来是目标 ID。
//
// BYTE Id[TargetCount];
//

BYTE SelfId;
BYTE Flags;

//
// 如果 Flags 是 PACKET_CHAT_FLAG_IN_GAME,那么接下来会有 Target。
//
// DWORD Target;
//

CHAR Message[1];
} Chat;
};
} GAME_PACKET, *PGAME_PACKET;

PSEND OldSend;

//
// 定位映像数据目录。
//

PVOID LocateImageDataDirectory(
__in PVOID ImageBase,
__in ULONG DataDirectory
)
{
PIMAGE_DOS_HEADER DosHeader;
PIMAGE_NT_HEADERS NtHeaders;

DosHeader = reinterpret_cast(ImageBase);
NtHeaders = Add2Ptr(ImageBase, DosHeader->e_lfanew, PIMAGE_NT_HEADERS);

//
// 从文件头中定位数据目录。
//

return Add2Ptr(ImageBase, NtHeaders->OptionalHeader.DataDirectory[DataDirectory].VirtualAddress, PVOID);
}

//
// 根据 DLL 文件名定位导入描述符。
//

PIMAGE_IMPORT_DESCRIPTOR LocateImportDescriptor(
__in PVOID ImageBase,
__in PSTR DllName
)
{
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;

//
// 定位导入描述符。
//

ImportDescriptor = reinterpret_cast(LocateImageDataDirectory(ImageBase,
IMAGE_DIRECTORY_ENTRY_IMPORT));

while (ImportDescriptor->Name) {
PSTR ImportedDllName;

//
// 比较 DLL 文件名。
//

ImportedDllName = Add2Ptr(ImageBase, ImportDescriptor->Name, PSTR);

if (!_strcmpi(DllName, ImportedDllName)) {
return ImportDescriptor;
}

ImportDescriptor++;
}

return NULL;
}

//
// 定位导入查找表。
//

PULONG_PTR LocateImportEntries(
__in PVOID ImageBase,
__in PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor,
__in BOOL LocateOriginalEntries
)
{
if (LocateOriginalEntries) {
return Add2Ptr(ImageBase, ImportDescriptor->OriginalFirstThunk, PULONG_PTR);
} else {
return Add2Ptr(ImageBase, ImportDescriptor->FirstThunk, PULONG_PTR);
}
}

//
// 比较导入查找表中的表项。
//
// 这个函数可以正确处理按照序号导入的表项。
//

BOOL CompareImportEntry(
__in PVOID ImageBase,
__in ULONG_PTR ImportedEntry,
__in PSTR EntryToLookup
)
{
if (IMAGE_SNAP_BY_ORDINAL(ImportedEntry) !=
IMAGE_SNAP_BY_ORDINAL(reinterpret_cast(EntryToLookup))) {
return FALSE;
}

if (IMAGE_SNAP_BY_ORDINAL(ImportedEntry)) {

//
// ImportedEntry 是一个函数的序号。也意味着 EntryToLookup 也是一个序号。
//

return IMAGE_ORDINAL(ImportedEntry) == IMAGE_ORDINAL(reinterpret_cast(EntryToLookup));
} else {

//
// 比较字符串。
//

return !strcmp(Add2Ptr(ImageBase, ImportedEntry, PSTR), EntryToLookup);
}
}

//
// 查找导入查找表表项。
//
// 如果 ProcName 是一个序号,那么它的最高位需要被设为 1。
//

DWORD LookupImportEntryIndex(
__in PVOID ImageBase,
__in PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor,
__in PSTR ProcName
)
{
DWORD Index;
PULONG_PTR Entries;

Index = 0;

//
// 定位导入查找表。
//

Entries = LocateImportEntries(ImageBase, ImportDescriptor, TRUE);

//
// 遍历导入查找表。
//

while (ULONG_PTR Offset = Entries[Index]) {

//
// 比较函数名 / 序号。
//

if (CompareImportEntry(ImageBase, Offset, ProcName)) {
return Index;
}

Index++;
}

return ENTRY_NOT_FOUND;
}

//
// IAT HOOK。
//

PVOID InterceptImportedProc(
__in PTSTR TargetName,
__in PSTR DllName,
__in PSTR ProcName,
__in PVOID HookProc
)
{
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
DWORD ImportEntryIndex;
PULONG_PTR Entries;
PVOID TargetBase;

//
// 定位要 HOOK 的模块。
//

TargetBase = reinterpret_cast(GetModuleHandle(TargetName));

//
// 定位导入描述符。
//

ImportDescriptor = LocateImportDescriptor(TargetBase, DllName);

//
// 查找导入的函数的索引。
//

ImportEntryIndex = LookupImportEntryIndex(TargetBase, ImportDescriptor, ProcName);

//
// 定位导入函数的地址表。
//

Entries = LocateImportEntries(TargetBase, ImportDescriptor, FALSE);

//
// 读取当前地址并替换。
//

return reinterpret_cast(InterlockedExchange(reinterpret_cast(&Entries[ImportEntryIndex]),
reinterpret_cast(HookProc)));
}

//
// WSASend 的过滤函数。
//

DWORD NewSend(
__in SOCKET Socket,
__in_bcount(BufferSize) PVOID Buffer,
__in DWORD BufferSize,
__in DWORD Flags
)
{
PGAME_PACKET GamePacket, NewGamePacket;

GamePacket = reinterpret_cast(Buffer);

//
// 检测是否为发送消息的包。
//

if (GamePacket->Signature == PACKET_SIGNATURE && GamePacket->Operation == PACKET_CHAT) {
PSTR MessageBuffer;

//
// 标志位之前有 TargetCount 个 ID,每个 ID 占用一个 BYTE 的大小。
//

NewGamePacket = Add2Ptr(GamePacket, GamePacket->Chat.TargetCount * sizeof(BYTE), PGAME_PACKET);

if (NewGamePacket->Chat.Flags == PACKET_CHAT_FLAG_IN_GAME) {

//
// 如果 Flags == PACKET_CHAT_FLAG_IN_GAME,那么在消息正文之前还有一个 Target,占用一个 DWORD。
//

NewGamePacket = Add2Ptr(NewGamePacket, sizeof(DWORD), PGAME_PACKET);
}

MessageBuffer = NewGamePacket->Chat.Message;

//
// 比较命令。(MessageBuffer 是以 0 结尾的。)
//

if (!strcmp(MessageBuffer, COMMAND_KICK)) {

//
// 返回错误。游戏会自动断开连接。
//

return SOCKET_ERROR;
}
}

return OldSend(Socket, Buffer, BufferSize, Flags);
}

//
// DLL 入口点。
//

BOOL DllMain(
__in HINSTANCE DllBase,
__in DWORD Reason,
__reserved PVOID Reserved
)
{
if (Reason == DLL_PROCESS_ATTACH) {

//
// HOOK。
//

OldSend = reinterpret_cast(InterceptImportedProc(TEXT("war3.exe"), "wsock32.dll",
reinterpret_cast(ORDINAL_SEND | IMAGE_ORDINAL_FLAG), reinterpret_cast(NewSend)));

} else if (Reason == DLL_PROCESS_DETACH) {

//
// UNHOOK。
//

InterceptImportedProc(TEXT("war3.exe"), "wsock32.dll",
reinterpret_cast(ORDINAL_SEND | IMAGE_ORDINAL_FLAG), reinterpret_cast(OldSend));
}

return TRUE;
}

评论

4 条对“魔兽争霸 3 踢人内挂”的回复

  1. MBC 的头像
    MBC

    mix是什么文件格式啊= =

  2. NewbieCoder 的头像
    NewbieCoder

    @MBC 我也不知道,只知道会自动作为DLL加载- –

  3. XXXXXXX 的头像
    XXXXXXX

    用什麼去編譯的?DEV C好像不行,還是是我不會操作

    1. NewbieCoder 的头像
      NewbieCoder

      @XXXXXXX
      Microsoft Visual C++ 2012

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注