文章作者:MagicBear QQ130012321
信息来源:邪恶八进制信息安全团队( www.eviloctal.com)
最近在搞一个网络程序,出后不久被破解,于是弄了一些反HOOK的技术
经测试WPE,IPSniffer,XSniffer等等著名Sniffer均告失效
检测内容:
1. 子程序地址是否在DLL空间内
2. 检查本机是否有运行RAW SOCKET类Sniffer
3. 检查GetFuncAddress返回地址是否与从IAT表获取地址相同
4. 检查地址开头是否有JMP
5. 对程序地址进行CRC校验,防止修改主程序及DLL内地址而使保护失效
P.S 需要主程序配合校验
主要是主程序调用,然后同时在DLL内备份一份并做CRC校验备份,主程序在每次发送前都调用DLL校验一次,对网络用量大的可能-0-...........欢迎丟鸡旦
//
LvKrnl.cpp : Defines the entry point for the DLL application.
//
#include
"
stdafx.h
"
#include
<
winsock2.h
>

#define
MAX_PACK_LEN 65535
#define
MAX_HOSTNAME_LAN 255
#pragma
comment (lib , "ws2_32.lib")

DWORD GetFunctionAddress( HMODULE phModule,
char
*
pProcName )
{
if (!phModule)
return 0;
PIMAGE_DOS_HEADER pimDH = (PIMAGE_DOS_HEADER)phModule;
PIMAGE_NT_HEADERS pimNH = (PIMAGE_NT_HEADERS)((char*)phModule+pimDH->e_lfanew);
PIMAGE_EXPORT_DIRECTORY pimED = (PIMAGE_EXPORT_DIRECTORY)((DWORD)phModule+pimNH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD pExportSize = pimNH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
DWORD pResult = 0;

if ((DWORD)pProcName < 0x10000)
{
if ((DWORD)pProcName >= pimED->NumberOfFunctions+pimED->Base || (DWORD)pProcName < pimED->Base)
return 0;
pResult = (DWORD)phModule+((DWORD*)((DWORD)phModule+pimED->AddressOfFunctions))[(DWORD)pProcName-pimED->Base];
}else
{
DWORD* pAddressOfNames = (DWORD*)((DWORD)phModule+pimED->AddressOfNames);
for (int i=0;i<pimED->NumberOfNames;i++)
{
char* pExportName = (char*)(pAddressOfNames[i]+(DWORD)phModule);
if (strcmp(pProcName,pExportName) == 0)
{
WORD* pAddressOfNameOrdinals = (WORD*)((DWORD)phModule+pimED->AddressOfNameOrdinals);
pResult = (DWORD)phModule+((DWORD*)((DWORD)phModule+pimED->AddressOfFunctions))[pAddressOfNameOrdinals[i]];
break;
}
}
}
if (pResult != 0 && pResult >= (DWORD)pimED && pResult < (DWORD)pimED+pExportSize)
{
char* pDirectStr = (char*)pResult;
bool pstrok = false;
while (*pDirectStr)
{
if (*pDirectStr == '.')
{
pstrok = true;
break;
}
pDirectStr++;
}
if (!pstrok)
return 0;
char pdllname[MAX_PATH];
int pnamelen = pDirectStr-(char*)pResult;
if (pnamelen <= 0)
return 0;
memcpy(pdllname,(char*)pResult,pnamelen);
pdllname[pnamelen] = 0;
HMODULE phexmodule = GetModuleHandle(pdllname);
pResult = GetFunctionAddress(phexmodule,pDirectStr+1);
}

return pResult;
}

BOOL RawSnifferCheck()
{
SOCKET SockRaw,Sock;
WSADATA wsaData;
int ret=0;
struct sockaddr_in sAddr,addr;
char RecvBuf[MAX_PACK_LEN];
char FAR name[MAX_HOSTNAME_LAN];

struct hostent FAR * pHostent;
char *Buf;
int settimeout=100;//这里我们设置了一秒钟超时
WSAStartup(MAKEWORD(2,2),&wsaData);
//建立一条RawSocket
SockRaw=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
//再建立一条UDP
Sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
memset(&sAddr,0,sizeof(sAddr));
memset(&addr,0,sizeof(addr));
sAddr.sin_family=AF_INET;
sAddr.sin_port=htons(35257);
addr.sin_family=AF_INET;

addr.sin_port=htons(35258);
//把IP地址指向本机
addr.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
memset(RecvBuf,0, sizeof(RecvBuf));
gethostname(name, MAX_HOSTNAME_LAN);
pHostent=gethostbyname(name);

//取得自己的IP地址
memcpy(&sAddr.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

//绑定一个本机的接收端口
bind(SockRaw, (struct sockaddr *)&sAddr, sizeof(sAddr));

//虚连接到本机的一个未打开的端口
connect(Sock,(struct sockaddr *)&addr,sizeof(addr));
Buf="1234567890!@#$%^&*";
//设置超时
setsockopt(SockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&settimeout,sizeof(int));
//向虚连接端口发送一个数据包
send(Sock,Buf,strlen(Buf),0);
//使用SockRaw尝试接收这个数据包
ret=recv(SockRaw,RecvBuf,sizeof(RecvBuf),0);
if(ret==SOCKET_ERROR || ret==0)
return true;
else
{
//进行ChkSum
if(Buf=="1234567890!@#$%^&*")
return false;
}
closesocket(Sock);
closesocket(SockRaw);

WSACleanup();
return true;
}

#define
MAIN_API extern "C" __declspec(dllexport)

FARPROC pconnect;
FARPROC psend;
FARPROC precv;
HINSTANCE hProcModule;

DWORD dwConnect,dwSend,dwRecv;

const
codesize
=
1048576
;

DWORD GetCRC32(
const
BYTE
*
pbData,
int
nSize);

BOOL checkJMP(
void
*
pFun)
{
LPBYTE pByte = (LPBYTE)pFun;

if(*pByte == 0xE9) //JMP CODE
{
return false;
}
if(((long)pFun < (long)hProcModule) || ((long)pFun > ((long)hProcModule + codesize)))
{
return false;
}
return true;
}

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
char syspath[256];
DWORD pcheck;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //注入进程运行
GetSystemDirectory(syspath,sizeof(syspath));
strcat(syspath,"/ws2_32.dll");
hProcModule = LoadLibrary(syspath);
if (hModule == NULL)
{
MessageBox(0,"Load library error!","Error",MB_ICONSTOP);
return false;
}
pconnect = GetProcAddress(hProcModule,"connect");
pcheck = GetFunctionAddress(hProcModule,"connect");
dwConnect = GetCRC32((unsigned char *)&pconnect,4);
if(!checkJMP(pconnect) || pcheck!=(unsigned long)pconnect){
MessageBox(0,"Load function connect error!","Error",MB_ICONSTOP);
return false;
}
psend = GetProcAddress(hProcModule,"send");
pcheck = GetFunctionAddress(hProcModule,"send");
dwSend = GetCRC32((unsigned char *)&psend,4);
if(!checkJMP(psend) || pcheck!=(unsigned long)psend){
MessageBox(0,"Load function send error!","Error",MB_ICONSTOP);
return false;
}
precv = GetProcAddress(hProcModule,"recv");
pcheck = GetFunctionAddress(hProcModule,"recv");
dwRecv = GetCRC32((unsigned char *)&precv,4);
if(!checkJMP(precv) || pcheck!=(unsigned long)precv){
MessageBox(0,"Load function recv error!","Error",MB_ICONSTOP);
return false;
}
if (!RawSnifferCheck())
{
MessageBox(0,"Wanring: Find a sniffer in local computer, please check virus!","Error",MB_ICONSTOP);
return false;
}
break;
case DLL_THREAD_ATTACH: //注入线程运行
break;
case DLL_THREAD_DETACH: //分离线程运行
break;
case DLL_PROCESS_DETACH: //分离进程运行
break;
}
return TRUE;
}

MAIN_API unsigned
long
KrnlLo(
int
vdcode,
void
*
c_connect,
void
*
c_send,
void
*
c_recv,
int
chkey)
{
if (vdcode != 0x123456) //确认是否为主程序调用
{
return 0;
}
if (GetTickCount()-chkey > 1000)
{
return 0;
}
if(!checkJMP(pconnect))
return false;
if(!checkJMP(psend))
return false;
if(!checkJMP(precv))
return false;
if (dwConnect != GetCRC32((unsigned char *)&pconnect,4) || dwSend != GetCRC32((unsigned char *)&psend,4) || dwRecv != GetCRC32((unsigned char *)&precv,4))
{
return 0;
}
if (c_connect != pconnect || c_send != psend || c_recv != precv)
{
return 123456789 ^ chkey;// 成功
}
return 0; //失败
}

/
//
GetCRC32: 求字节流的CRC32校验码
//
参数:
//
pbData: 指向字节流缓冲区首地址
//
nSize: 字节流长度
//
//
返回值:
//
字节流的CRC32校验码
//
//
这里使用查表法求CRC32校验码,这部分是参考老罗的文章《 矛与盾的较量(2)——CRC原理篇》该写的。
//
原文的具体内容请参看: [url]
http://asp.7i24.com/netcool/laoluo/articles/show_article.asp?Article_ID=15
[/url]
//
//
下面使用内联汇编求CRC32校验码,充分使用了CPU中的寄存器,速度和方便性都是使用C/C++所不能比拟的
//
DWORD GetCRC32(
const
BYTE
*
pbData,
int
nSize)
{
DWORD dwCRC32Table[256];

__asm //这片内联汇编是初始化CRC32表
{
MOV ECX, 256

_NextTable:
LEA EAX, [ECX-1]
PUSH ECX
MOV ECX, 8

_NextBit:
SHR EAX, 1
JNC _NotCarry
XOR EAX, 0xEDB88320
_NotCarry:
DEC ECX
JNZ _NextBit

POP ECX
MOV [dwCRC32Table + ECX*4 - 4], EAX
DEC ECX
JNZ _NextTable
}

__asm //下面是求CRC32校验码
{
MOV EAX, -1
MOV EBX, pbData
OR EBX, EBX
JZ _Done
MOV ECX, nSize
OR ECX, ECX
JZ _Done

_NextByte:
MOV DL, [EBX]

XOR DL, AL
MOVZX EDX, DL
SHR EAX, 8
XOR EAX, [dwCRC32Table + EDX*4]

INC EBX
LOOP _NextByte
_Done:
NOT EAX
}
}
////
信息来源:邪恶八进制信息安全团队( www.eviloctal.com)
最近在搞一个网络程序,出后不久被破解,于是弄了一些反HOOK的技术
经测试WPE,IPSniffer,XSniffer等等著名Sniffer均告失效
检测内容:
1. 子程序地址是否在DLL空间内
2. 检查本机是否有运行RAW SOCKET类Sniffer
3. 检查GetFuncAddress返回地址是否与从IAT表获取地址相同
4. 检查地址开头是否有JMP
5. 对程序地址进行CRC校验,防止修改主程序及DLL内地址而使保护失效
P.S 需要主程序配合校验
主要是主程序调用,然后同时在DLL内备份一份并做CRC校验备份,主程序在每次发送前都调用DLL校验一次,对网络用量大的可能-0-...........欢迎丟鸡旦















































































































































































































































































































