Coder Social home page Coder Social logo

luispater / dezend Goto Github PK

View Code? Open in Web Editor NEW
66.0 66.0 42.0 6.53 MB

DeZend 源代码

C 78.92% C++ 4.70% PHP 1.06% Shell 1.39% Objective-C 11.22% GDB 0.07% Makefile 0.11% Roff 0.24% M4 1.14% JavaScript 0.06% Lex 0.57% Yacc 0.32% Batchfile 0.01% HTML 0.20%

dezend's People

Contributors

luispater avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dezend's Issues

missing files include/Encode.h, include/Encode.c, common/Hash.h, common/Hash.c

+ files below are missing (20131004 FOUND)
+ `attached below` (20170418 EDIT)
+ mistake or compile issue may not resolved
  find its SVN version first may help
+ 拍黄片**! Heil Pai Huang Pian (PHP Joke in Chinese)

, include/Encode.h

/*
///////////////////////////////////////////////////////////////////////////////
//
//  FileName    :   Encode.h
//  Version     :   1.0
//  Creator     :   RM
//  Create Date :   2006-01-01
//  Comment     :
//
///////////////////////////////////////////////////////////////////////////////
*/

#ifndef __ENCODE_H__
#define __ENCODE_H__

#ifdef __cplusplus
extern "C"
{
#endif

/*
///////////////////////////////////////////////////////////////////////////////
// D E F I N E S
///////////////////////////////////////////////////////////////////////////////
*/
typedef enum _DES_CRYPT_TYPE {
    DES_ENCRYPT,
    DES_DECRYPT
} DES_CRYPT_TYPE;

/* Type of struct */
#define TYPE_ENCODE_INTERNAL 0x1000
#define TYPE_ENCODE_GLOBAL 0x2000
#define TYPE_ENCODE_LOCAL 0x4000

/* Default settings */
#define DEFAULT_ENCODE_KEY_PRINT _T( "amaworld" )
#define DEFAULT_ENCODE_KEY {\
    _T( 'a' ) ^ XOR_STR, _T( 'm' ) ^ XOR_STR, _T( 'a' ) ^ XOR_STR, _T( 'w' ) ^ XOR_STR,\
    _T( 'o' ) ^ XOR_STR, _T( 'r' ) ^ XOR_STR, _T( 'l' ) ^ XOR_STR, _T( 'd' ) ^ XOR_STR,\
    _T( '\0' ) ^ XOR_STR,\
}
#define DEFAULT_ENCODE_KEY_LENGTH ( SIZE_OF_ARRAY( DEFAULT_ENCODE_KEY_PRINT ) - 1 )
#define MAX_ENCODE_KEY_LENGTH 16

/* Flags */
#define ES_FLAGS_ENCODE_STEP1 0x1
#define ES_FLAGS_ENCODE_STEP2 0x2
#define ES_FLAGS_ENCODE_STEP3 0x3
#define ES_FLAGS_ENCODE_STEP4 0x4

#define ES_FLAGS_ENCODE_STEP_MASK 0xFF

#define ES_FLAGS_REMOVE_PROTECTION 0x08000000

#define ES_FLAGS_ENCODE_1 0x10000000
#define ES_FLAGS_ENCODE_2 0x20000000
#define ES_FLAGS_ENCODE_3 0x40000000
#define ES_FLAGS_ENCODE_4 0x80000000

#define ES_FLAGS_ENCODE 0xF0000000

#define ES_FLAGS_CRC_FILE 0x1000
#define ES_FLAGS_CRC_MODULE 0x2000
#define ES_FLAGS_MD5_FILE 0x4000
#define ES_FLAGS_MD5_MODULE 0x8000

/*
///////////////////////////////////////////////////////////////////////////////
// S T R U C T U R E S
///////////////////////////////////////////////////////////////////////////////
*/
typedef struct _MD5_VALUE {
    unsigned char Value[16];
} MD5_VALUE, *PMD5_VALUE;

typedef struct _ENCODE_RANGE {
    PVOID Start;
    PVOID End;
    ULONG Flags;
} ENCODE_RANGE, *PENCODE_RANGE;

typedef struct _ENCODE_STUB {
    USHORT Type;
    USHORT Size;
    ULONG Flags;
    ULONG Protection;
    UCHAR Key[MAX_ENCODE_KEY_LENGTH];
    ULONG KeyLength;
    UCHAR InternalKey[MAX_ENCODE_KEY_LENGTH];
    ULONG InternalKeyLength;
    MD5_VALUE MD5;
    ULONG Count;
    PENCODE_RANGE Range;
} ENCODE_STUB, *PENCODE_STUB;

/*
///////////////////////////////////////////////////////////////////////////////
// G L O B A L S
///////////////////////////////////////////////////////////////////////////////
*/

/*
///////////////////////////////////////////////////////////////////////////////
// F U N C T I O N S
///////////////////////////////////////////////////////////////////////////////
*/
ULONG DesCode( void *Out, const void *In, ULONG Length, const void *Key, ULONG KeyLength, ULONG Type );
void EncodeKey( UCHAR *Key, ULONG KeyLength );
void DecodeKey( UCHAR *Key, ULONG KeyLength );
void ObfuscateKey( UCHAR *Key, ULONG KeyLength );
void EncodeEx( UCHAR *Buffer, ULONG Length, UCHAR *Key, ULONG KeyLength );
void DecodeEx( UCHAR *Buffer, ULONG Length, UCHAR *Key, ULONG KeyLength );

ULONG DecodeStubKey( PENCODE_STUB Stub, const TCHAR *ModuleName );

void RemoveCodeProtection( PVOID ModuleBase );
void RecoverCodeProtection( PVOID ModuleBase );

void EncodeInternalStub( PENCODE_STUB Stub, PVOID ImageBase, PVOID FileImage );
void DecodeInternalStub( PENCODE_STUB Stub );
void EncodeStub( PENCODE_STUB Stub, PVOID ImageBase, PVOID FileImage );
void DecodeStub( PENCODE_STUB Stub );

void GetCRC( PMD5_VALUE MD5, UCHAR *Buffer, ULONG BufferLength );
void GetMD5( PMD5_VALUE MD5, UCHAR *Buffer, ULONG BufferLength );
ULONG GetFileCRC( PMD5_VALUE CRCPtr, const TCHAR *FileName, ULONG SkipOffset, ULONG SkipSize );
ULONG GetModuleCRC( PMD5_VALUE MD5, LPVOID ModuleBase, ULONG SkipOffset, ULONG SkipSize );
ULONG GetFileMD5( PMD5_VALUE MD5, const TCHAR *FileName, ULONG SkipOffset, ULONG SkipSize );
ULONG GetModuleMD5( PMD5_VALUE MD5, LPVOID ModuleBase, ULONG SkipOffset, ULONG SkipSize );

ULONG CheckIfTrace( );

void DestroyCode( PUCHAR AddressStart, PUCHAR AddressEnd );
void AlterCode( PUCHAR AddressStart, PUCHAR AddressEnd );

#ifdef __cplusplus
}
#endif
/*
///////////////////////////////////////////////////////////////////////////////
// E N D  O F  F I L E
///////////////////////////////////////////////////////////////////////////////
*/
#endif /* __ENCODE_H__ */

, include/Encode.c

/*
///////////////////////////////////////////////////////////////////////////////
//
//  FileName    :   Encode.c
//  Version     :   1.0
//  Creator     :   RM
//  Create Date :   2006-01-01
//  Comment     :
//
///////////////////////////////////////////////////////////////////////////////
*/

#include < tchar.h >
#include < stdio.h >
#include < stdarg.h >
#include < malloc.h >

#ifdef _MSC_VER
#include < windows.h >
#else
#include "Compatible.h"
#endif

#include "Macro.h"
#include "Map.h"
#include "MD5.h"
#include "AddLog.h"
#include "Dump.h"
#include "Encode.h"

/* Skip warning */
#pragma warning( disable: 4054 )
#pragma warning( disable: 4055 )
#pragma warning( disable: 4100 )
#pragma warning( disable: 4127 )
#pragma warning( disable: 4152 )
#pragma warning( disable: 4201 )
#pragma warning( disable: 4204 )
#pragma warning( disable: 4244 )
#pragma warning( disable: 4245 )
#pragma warning( disable: 4305 )
#pragma warning( disable: 4310 )
#pragma warning( disable: 4505 )
#pragma warning( disable: 4706 )

/*
///////////////////////////////////////////////////////////////////////////////
// D E F I N E S
///////////////////////////////////////////////////////////////////////////////
*/
/* Des */
#define DEFAULT_XOR 0xA5A5

/* CRC32 */
#define CRC32( CRC, Ch ) CRC = ( ( CRC >> 8 ) & 0x00FFFFFF ) ^ g_CRC32Table[( CRC ^ ( Ch ) ) & 0xFF]

/* Check if hook */
#define OP_CODE_INT3 0xCC /* INT 3 */
#define OP_CODE_PUSH 0x68 /* PUSH */
#define OP_CODE_RET 0xC3 /* RET */
#define OP_CODE_CALL 0xE8 /* CALL data32 */
#define OP_CODE_JMP 0xE9 /* JMP data32 */
#define OP_CODE_JMP_FAR 0xEA /* JMP data16:data32 */
#define OP_CODE_JMP_NEAR 0xEB /* JMP data8 */

/* Get global */
#define GET_INTERNAL_STUB( ) g_InternalStubPtr

/*
///////////////////////////////////////////////////////////////////////////////
// S T R U C T U R E S
///////////////////////////////////////////////////////////////////////////////
*/
typedef BOOL ( WINAPI *IsDebuggerPresentProc ) ( );
typedef BOOL ( WINAPI *VirtualProtectProc ) ( LPVOID, DWORD, DWORD, PDWORD );

typedef UCHAR ( DES_SUBKEY )[16] [48];
typedef DES_SUBKEY *PDES_SUBKEY;

/*
///////////////////////////////////////////////////////////////////////////////
// G L O B A L S
///////////////////////////////////////////////////////////////////////////////
*/
static UCHAR g_DummyStart[4] = {
    0, 1, 0, 1
};

static UINT g_CRC32Table[256] = {
    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
    0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
    0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
    0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
    0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
    0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
    0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
    0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
    0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
    0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
    0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
    0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
    0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
    0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
    0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
    0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
    0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
    0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
    0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
    0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
    0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
};

/* Initial permutation IP */
static UCHAR IP_Table[64] = {
    58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
    62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
    57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
    61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
};
/* Final permutation IP^-1 */
static UCHAR IPR_Table[64] = {
    40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31,
    38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29,
    36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27,
    34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25
};
/* Expansion operation matrix */
static UCHAR E_Table[48] = {
    32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9,
        8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
    16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25,
    24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1
};
/* 32-bit permutation function P used on the output of the S-boxes */
static UCHAR P_Table[32] = {
    16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
    2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
};
/* Permuted choice table (Key) */
static UCHAR PC1_Table[56] = {
    57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
    10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
    63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
    14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
};
/* Permuted choice key (table) */
static UCHAR PC2_Table[48] = {
    14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
    23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
    41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
    44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32
};
/* Number left rotations of pc1 */
static UCHAR LOOP_Table[16] = {
    1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
/* The (in)famous S-boxes */
static UCHAR S_Box[8] [4] [16] = {
    /* S1 */
    14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
    0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
    4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
    15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
    /* S2 */
    15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
    3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
    0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
    13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
    /* S3 */
    10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
    13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
    13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
    1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
    /* S4 */
    7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
    13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
    10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
    3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
    /* S5 */
    2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
    14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
    4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
    11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
    /* S6 */
    12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
    10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
    9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
    4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
    /* S7 */
    4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
    13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
    1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
    6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
    /* S8 */
    13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
    1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
    7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
    2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11
};
static UCHAR g_DummyEnd[4] = {
    0, 1, 0, 1
};

void EncodeDummyStart( );
void EncodeDummyEnd( );

ENCODE_RANGE g_InternalRange[] = {
    { g_DummyStart, g_DummyEnd, ES_FLAGS_ENCODE_1 },
    { EncodeDummyStart, EncodeDummyEnd, ES_FLAGS_ENCODE_1 },
};

ENCODE_STUB g_InternalStub = {
    TYPE_ENCODE_INTERNAL,
    sizeof( ENCODE_STUB ),
    0,
    0,
    DEFAULT_ENCODE_KEY,
    DEFAULT_ENCODE_KEY_LENGTH,
    { 0 },
    0,
    { 0 },
    SIZE_OF_ARRAY( g_InternalRange ),
    g_InternalRange
};
PENCODE_STUB g_InternalStubPtr = &g_InternalStub;

/*
///////////////////////////////////////////////////////////////////////////////
// F U N C T I O N S  P R O T O T Y P E
///////////////////////////////////////////////////////////////////////////////
*/
/* Standard DES encode/decode */
static void DES( UCHAR Out[8], const UCHAR In[8], const PDES_SUBKEY SubKey, ULONG Type );
static void SetKey( PDES_SUBKEY SubKey, ULONG *Is3DES, const UCHAR *Key, ULONG Length );
static void SetSubKey( PDES_SUBKEY SubKey, const UCHAR Key[8] );
static void F_Func( UCHAR In[32], const UCHAR Ki[48] );
static void S_Func( UCHAR Out[32], const UCHAR In[48] );
static void Transform( UCHAR *Out, const UCHAR *In, const UCHAR *Table, ULONG Length );
static void Xor( UCHAR *InA, const UCHAR *InB, ULONG Length );
static void RotateL( UCHAR *In, ULONG Length, ULONG Loop );
static void ByteToBit( UCHAR *Out, const UCHAR *In, ULONG Bits );
static void BitToByte( UCHAR *Out, const UCHAR *In, ULONG Bits );

/* Get executable file information */
ULONG GetPeInfo( PVOID, PIMAGE_NT_HEADERS*, PIMAGE_FILE_HEADER*, PIMAGE_OPTIONAL_HEADER*, PIMAGE_SECTION_HEADER* );

/*
///////////////////////////////////////////////////////////////////////////////
// F U N C T I O N S
///////////////////////////////////////////////////////////////////////////////
*/
void EncodeDummyStart( )
{
    /* Just for count */
}

ULONG DesCode( void *Out, const void *In, ULONG Length, const void *Key, ULONG KeyLength, ULONG Type )
{
    register int Iter;
    register int Count;
    ULONG Is3DES;
    ULONG Left;
    const UCHAR *UKey;
    register UCHAR *UOut;
    register const UCHAR *UIn;
    DES_SUBKEY SubKey[2]; /* 16 loop sub key */

    if ( Out == NULL || In == NULL || Key == NULL || Length == 0 )
        return FALSE;

    UKey = ( const UCHAR* )Key;
    SetKey( SubKey, &Is3DES, UKey, KeyLength );

    Left = Length & 7;
    Length &= ~7;
    if ( !Is3DES )
    {
        /* 1DES */
        UOut = ( UCHAR* )Out;
        UIn = ( const UCHAR* )In;
        for ( Iter = 0, Count = Length >> 3; Iter < Count; Iter++, UOut += 8, UIn += 8 )
            DES( UOut, UIn, &SubKey[0], Type );
        while ( Left )
        {
            *UOut = ( UCHAR ) ( *UIn ^ DEFAULT_XOR ^ UKey[Left % KeyLength] );
            UIn++;
            UOut++;
            Left--;
        }
    }
    else
    {
        /* 3DES */
        /* Encode: E(key0)-D(key1)-E(key0) */
        /* Decode: D(key0)-E(key1)-D(key0) */
        UOut = ( UCHAR* )Out;
        UIn = ( const UCHAR* )In;
        for ( Iter = 0, Count = Length >> 3; Iter < Count; Iter++, UOut += 8, UIn += 8 )
        {
            DES( UOut, UIn, &SubKey[0], Type );
            DES( UOut, UOut, &SubKey[1], !Type );
            DES( UOut, UOut, &SubKey[0], Type );
        }
        while ( Left )
        {
            *UOut = ( UCHAR ) ( *UIn ^ DEFAULT_XOR ^ UKey[Left % KeyLength] );
            UIn++;
            UOut++;
            Left--;
        }
    }

    return TRUE;
}

void SetKey( PDES_SUBKEY SubKey, ULONG *Is3DES, const UCHAR *Key, ULONG Length )
{
    UCHAR DesKey[16];
    memset( DesKey, 0, 16 );
    memcpy( DesKey, Key, Length > 16 ? 16 : Length );
    SetSubKey( &SubKey[0], &DesKey[0] );
    if ( Length > 8 )
    {
        SetSubKey( &SubKey[1], &DesKey[8] );
        if ( Is3DES )
            *Is3DES = TRUE;
    }
    else
    {
        if ( Is3DES )
            *Is3DES = FALSE;
    }
}

void DES( UCHAR Out[8], const UCHAR In[8], const PDES_SUBKEY SubKey, ULONG Type )
{
    register LONG Iter;
    UCHAR M[64];
    UCHAR Tmp[32];
    UCHAR *Li = &M[0];
    UCHAR *Ri = &M[32];

    ByteToBit( M, In, 64 );
    Transform( M, M, IP_Table, 64 );
    if ( Type == DES_ENCRYPT )
    {
        for ( Iter = 0; Iter < 16; Iter++ )
        {
            memcpy( Tmp, Ri, 32 );
            F_Func( Ri, ( *SubKey )[Iter] );
            Xor( Ri, Li, 32 );
            memcpy( Li, Tmp, 32 );
        }
    }
    else
    {
        for ( Iter = 15; Iter >= 0; Iter-- )
        {
            memcpy( Tmp, Li, 32 );
            F_Func( Li, ( *SubKey )[Iter] );
            Xor( Li, Ri, 32 );
            memcpy( Ri, Tmp, 32 );
        }
    }
    Transform( M, M, IPR_Table, 64 );
    BitToByte( Out, M, 64 );
}

void SetSubKey( PDES_SUBKEY SubKey, const UCHAR Key[8] )
{
    register ULONG Iter;
    UCHAR K[64];
    UCHAR *KL = &K[0];
    UCHAR *KR = &K[28];
    ByteToBit( K, Key, 64 );
    Transform( K, K, PC1_Table, 56 );
    for ( Iter = 0; Iter < 16; Iter++ )
    {
        RotateL( KL, 28, LOOP_Table[Iter] );
        RotateL( KR, 28, LOOP_Table[Iter] );
        Transform( ( *SubKey )[Iter], K, PC2_Table, 48 );
    }
}

void F_Func( UCHAR In[32], const UCHAR Ki[48] )
{
    UCHAR MR[48];
    Transform( MR, In, E_Table, 48 );
    Xor( MR, Ki, 48 );
    S_Func( In, MR );
    Transform( In, In, P_Table, 32 );
}

void S_Func( UCHAR Out[32], const UCHAR In[48] )
{
    register UCHAR Iter, Jter, Kter;
    for ( Iter = 0; Iter < 8; Iter++, In += 6, Out += 4 )
    {
        Jter = ( UCHAR ) ( ( In[0] << 1 ) + In[5] );
        Kter = ( UCHAR ) ( ( In[1] << 3 ) + ( In[2] << 2 ) + ( In[3] << 1 ) + In[4] );
        ByteToBit( Out, &S_Box[Iter] [Jter] [Kter], 4 );
    }
}

void Transform( UCHAR *Out, const UCHAR *In, const UCHAR *Table, ULONG Length )
{
    register ULONG Iter;
    UCHAR Tmp[256];
    for ( Iter = 0; Iter < Length; Iter++ )
        Tmp[Iter] = In[Table[Iter] - 1];
    memcpy( Out, Tmp, Length );
}

void Xor( UCHAR *InA, const UCHAR *InB, ULONG Length )
{
    register ULONG Iter;
    for ( Iter = 0; Iter < Length; Iter++ )
        InA[Iter] ^= InB[Iter];
}

void RotateL( UCHAR *In, ULONG Length, ULONG Loop )
{
    UCHAR Tmp[256];
    memcpy( Tmp, In, Loop );
    memcpy( In, In + Loop, Length - Loop );
    memcpy( In + Length - Loop, Tmp, Loop );
}

void ByteToBit( UCHAR *Out, const UCHAR *In, ULONG Bits )
{
    register ULONG Iter;
    for ( Iter = 0; Iter < Bits; Iter++ )
        Out[Iter] = ( UCHAR ) ( ( In[Iter >> 3] >> ( Iter & 7 ) ) & 1 );
}

void BitToByte( UCHAR *Out, const UCHAR *In, ULONG Bits )
{
    register ULONG Iter;
    memset( Out, 0, Bits >> 3 );
    for ( Iter = 0; Iter < Bits; Iter++ )
        Out[Iter >> 3] |= In[Iter] << ( Iter & 7 );
}

void GetCRC( PMD5_VALUE MD5, UCHAR *Buffer, ULONG BufferLength )
{
    register ULONG Iter;
    register UCHAR *BufferPtr;
    unsigned __int64 Sum = 0;
    UINT CRC = 0;

    for ( Iter = BufferLength, BufferPtr = Buffer; Iter--; BufferPtr++ )
    {
        Sum += *BufferPtr;
        /* Use default crc32 */
        CRC32( CRC, *BufferPtr );
    }

    *( ( UINT* )&MD5->Value[0] ) += CRC;
    *( ( UINT* )&MD5->Value[4] ) += BufferLength;
    *( ( unsigned __int64* )&MD5->Value[8] ) += Sum;
}

ULONG GetFileCRC( PMD5_VALUE MD5, const TCHAR *FileName, ULONG SkipOffset, ULONG SkipSize )
{
    ULONG Size;
    PVOID FileImage;

    MapFileEx( FileName, &FileImage, &Size, NULL, MAP_FILE_READ | MAP_FILE_GENERIC_READ | MAP_FILE_SHARE_READ );
    if ( FileImage )
    {
        memset( MD5, 0, sizeof( *MD5 ) );
        GetCRC( MD5, ( UCHAR* )FileImage, SkipOffset );
        GetCRC( MD5, ( UCHAR* )FileImage + SkipOffset + SkipSize, Size - SkipOffset - SkipSize );
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG GetModuleCRC( PMD5_VALUE MD5, LPVOID ModuleBase, ULONG SkipOffset, ULONG SkipSize )
{
    register ULONG Iter;
    register ULONG Count;
    PIMAGE_NT_HEADERS NtHeaders;
    PIMAGE_FILE_HEADER FileHeader;
    PIMAGE_OPTIONAL_HEADER OptionalHeader;
    PIMAGE_SECTION_HEADER SectionHeader;
    ULONG Size;
    UCHAR *StartAddress;
    UCHAR *SkipAddressStart;
    UCHAR *SkipAddressEnd;

    if ( GetPeInfo( ModuleBase, &NtHeaders, &FileHeader, &OptionalHeader, &SectionHeader ) )
    {
        memset( MD5, 0, sizeof( *MD5 ) );
        SkipAddressStart = ( UCHAR* )ModuleBase + SkipOffset;
        SkipAddressEnd = SkipAddressStart + SkipSize;
        for ( Iter = 0, Count = FileHeader->NumberOfSections; Iter < Count; Iter++, SectionHeader++ )
        {
            if ( !( SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE ) && *( ( ULONG* )SectionHeader->Name ) != 0x6164722e )
            {
                StartAddress = ( UCHAR* )ModuleBase + SectionHeader->VirtualAddress;
                Size = SectionHeader->SizeOfRawData;
                if ( StartAddress <= SkipAddressStart && SkipAddressEnd < StartAddress + Size )
                {
                    GetCRC( MD5, StartAddress, SkipOffset );
                    GetCRC( MD5, SkipAddressEnd, Size - SkipOffset - SkipSize );
                }
                else
                {
                    GetCRC( MD5, StartAddress, Size );
                }
            }
        }
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

void GetMD5( PMD5_VALUE MD5, UCHAR *Buffer, ULONG BufferLength )
{
    MD5_CTX MD5Ctx;
    MD5Init( &MD5Ctx );
    MD5Update( &MD5Ctx, Buffer, BufferLength );
    MD5Final( MD5->Value, &MD5Ctx );
}

ULONG GetFileMD5( PMD5_VALUE MD5, const TCHAR *FileName, ULONG SkipOffset, ULONG SkipSize )
{
    ULONG Size;
    PVOID FileImage;
    MD5_CTX MD5Ctx;

    MapFileEx( FileName, &FileImage, &Size, NULL, MAP_FILE_READ | MAP_FILE_GENERIC_READ | MAP_FILE_SHARE_READ );
    if ( FileImage )
    {
        MD5Init( &MD5Ctx );
        if ( SkipSize )
        {
            MD5Update( &MD5Ctx, ( UCHAR* )FileImage, SkipOffset );
            MD5Update( &MD5Ctx, ( UCHAR* )FileImage + SkipOffset + SkipSize, Size - SkipOffset - SkipSize );
        }
        else
        {
            MD5Update( &MD5Ctx, ( UCHAR* )FileImage, Size );
        }
        MD5Final( MD5->Value, &MD5Ctx );
        UnMapFile( FileImage );
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG GetModuleMD5( PMD5_VALUE MD5, LPVOID ModuleBase, ULONG SkipOffset, ULONG SkipSize )
{
    register ULONG Iter;
    register ULONG Count;
    PIMAGE_NT_HEADERS NtHeaders;
    PIMAGE_FILE_HEADER FileHeader;
    PIMAGE_OPTIONAL_HEADER OptionalHeader;
    PIMAGE_SECTION_HEADER SectionHeader;
    ULONG Size;
    UCHAR *StartAddress;
    UCHAR *SkipAddressStart;
    UCHAR *SkipAddressEnd;
    MD5_CTX MD5Ctx;

    if ( GetPeInfo( ModuleBase, &NtHeaders, &FileHeader, &OptionalHeader, &SectionHeader ) )
    {
        memset( MD5, 0, sizeof( *MD5 ) );
        SkipAddressStart = ( UCHAR* )ModuleBase + SkipOffset;
        SkipAddressEnd = SkipAddressStart + SkipSize;
        for ( Iter = 0, Count = FileHeader->NumberOfSections; Iter < Count; Iter++, SectionHeader++ )
        {
            if ( !( SectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE ) && *( ( ULONG* )SectionHeader->Name ) != 0x6164722e )
            {
                StartAddress = ( UCHAR* )ModuleBase + SectionHeader->VirtualAddress;
                Size = SectionHeader->SizeOfRawData;
                if ( StartAddress <= SkipAddressStart && SkipAddressEnd < StartAddress + Size )
                {
                    MD5Update( &MD5Ctx, StartAddress, SkipOffset );
                    MD5Update( &MD5Ctx, SkipAddressEnd, Size - SkipOffset - SkipSize );
                }
                else
                {
                    MD5Update( &MD5Ctx, StartAddress, Size );
                }
            }
        }
        MD5Final( MD5->Value, &MD5Ctx );
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG DecodeStubKey( PENCODE_STUB Stub, const TCHAR *ModuleName )
{
    ULONG RetCode;
    ULONG Flags;
    MD5_VALUE MD5;
    ULONG Size;
    UCHAR *Module;
    UCHAR *SkipAddress;

    if ( Stub == NULL )
        Stub = GET_INTERNAL_STUB( );

    Flags = GET_INTERNAL_STUB( )->Flags;
    if ( Flags & ES_FLAGS_CRC_FILE )
    {
        Size = sizeof( MD5 );
        SkipAddress = ( UCHAR* )GET_INTERNAL_STUB( );
        Module = ( UCHAR* )GetModuleHandle( ModuleName );
        RetCode = GetFileCRC( &MD5, ModuleName, SkipAddress - Module, sizeof( ENCODE_STUB ) );
    }
    else if ( Flags & ES_FLAGS_CRC_MODULE )
    {
        Size = sizeof( MD5 );
        SkipAddress = ( UCHAR* )GET_INTERNAL_STUB( );
        Module = ( UCHAR* )GetModuleHandle( ModuleName );
        RetCode = GetModuleCRC( &MD5, Module, SkipAddress - Module, sizeof( ENCODE_STUB ) );
    }
    else if ( Flags & ES_FLAGS_MD5_FILE )
    {
        Size = sizeof( MD5 );
        SkipAddress = ( UCHAR* )GET_INTERNAL_STUB( );
        Module = ( UCHAR* )GetModuleHandle( ModuleName );
        RetCode = GetFileMD5( &MD5, ModuleName, SkipAddress - Module, sizeof( ENCODE_STUB ) );
    }
    else if ( Flags & ES_FLAGS_MD5_MODULE )
    {
        Size = sizeof( MD5 );
        SkipAddress = ( UCHAR* )GET_INTERNAL_STUB( );
        Module = ( UCHAR* )GetModuleHandle( ModuleName );
        RetCode = GetModuleMD5( &MD5, Module, SkipAddress - Module, sizeof( ENCODE_STUB ) );
    }
    else
    {
        RetCode = FALSE;
    }

    if ( RetCode )
        DecodeEx( Stub->Key, Stub->KeyLength, Stub->MD5.Value, sizeof( Stub->MD5.Value ) );

    return RetCode;
}

ULONG CheckIfHook( UCHAR *Buffer, ULONG Length )
{
    register ULONG Iter;
    register ULONG Count;
    register UCHAR *BufferPtr;
    LONG Address;

    BufferPtr = Buffer;
    Count = Length;
    for ( Iter = 0; Iter < Count; Iter++, BufferPtr++ )
    {
        switch ( *BufferPtr )
        {
        case OP_CODE_INT3 :
            return TRUE;
        case OP_CODE_PUSH :
            if ( BufferPtr[1] == OP_CODE_RET )
            {
                Address = *( ( LONG* ) ( BufferPtr + 2 ) );
                if ( Address < 0 )
                    return TRUE;
            }
            break;
        case OP_CODE_CALL :
            Address = *( ( LONG* ) ( BufferPtr + 2 ) );
            if ( Address < 0 )
                return TRUE;
            break;
        case OP_CODE_JMP :
            Address = *( ( LONG* ) ( BufferPtr + 2 ) );
            if ( Address < 0 )
                return TRUE;
            break;
        case OP_CODE_JMP_FAR :
            Address = *( ( LONG* ) ( BufferPtr + 2 ) );
            if ( Address < 0 )
                return TRUE;
            break;
        case OP_CODE_JMP_NEAR :
            Address = *( ( CHAR* ) ( BufferPtr + 2 ) );
            if ( Address < 0 )
                return TRUE;
            break;
        }
    }

    return FALSE;
}

ULONG CheckIfTrace( )
{
    ULONG Count;
    static HMODULE hKernel32 = NULL;
    static VirtualProtectProc VirtualProtect = NULL;
    static IsDebuggerPresentProc IsDebuggerPresent = NULL;
    static TCHAR tszkernel32[] = {
        _T( 'k' ) ^ XOR_STR, _T( 'e' ) ^ XOR_STR, _T( 'r' ) ^ XOR_STR, _T( 'n' ) ^ XOR_STR,
        _T( 'e' ) ^ XOR_STR, _T( 'l' ) ^ XOR_STR, _T( '3' ) ^ XOR_STR, _T( '2' ) ^ XOR_STR,
        _T( '.' ) ^ XOR_STR, _T( 'd' ) ^ XOR_STR, _T( 'l' ) ^ XOR_STR, _T( 'l' ) ^ XOR_STR,
        _T( '\0' ) ^ XOR_STR,
    };
    static CHAR aszVirtualProtect[] = {
        ( 'V' ) ^ XOR_STR, ( 'i' ) ^ XOR_STR, ( 'r' ) ^ XOR_STR, ( 't' ) ^ XOR_STR,
        ( 'u' ) ^ XOR_STR, ( 'a' ) ^ XOR_STR, ( 'l' ) ^ XOR_STR, ( 'P' ) ^ XOR_STR,
        ( 'r' ) ^ XOR_STR, ( 'o' ) ^ XOR_STR, ( 't' ) ^ XOR_STR, ( 'e' ) ^ XOR_STR,
        ( 'c' ) ^ XOR_STR, ( 't' ) ^ XOR_STR, ( '\0' ) ^ XOR_STR,
    };
    static CHAR aszIsDebuggerPresent[] = {
        ( 'I' ) ^ XOR_STR, ( 's' ) ^ XOR_STR, ( 'D' ) ^ XOR_STR, ( 'e' ) ^ XOR_STR,
        ( 'b' ) ^ XOR_STR, ( 'u' ) ^ XOR_STR, ( 'g' ) ^ XOR_STR, ( 'g' ) ^ XOR_STR,
        ( 'e' ) ^ XOR_STR, ( 'r' ) ^ XOR_STR, ( 'P' ) ^ XOR_STR, ( 'r' ) ^ XOR_STR,
        ( 'e' ) ^ XOR_STR, ( 's' ) ^ XOR_STR, ( 'e' ) ^ XOR_STR, ( 'n' ) ^ XOR_STR,
        ( 't' ) ^ XOR_STR, ( '\0' ) ^ XOR_STR,
    };

    if ( hKernel32 == NULL )
    {
        DECODE_STR( Count, tszkernel32 );
        hKernel32 = GetModuleHandle( tszkernel32 );
        ENCODE_STR( Count, tszkernel32 );
    }

    if ( VirtualProtect == NULL )
    {
        if ( hKernel32 )
        {
            DECODE_STR( Count, aszVirtualProtect );
            VirtualProtect = ( VirtualProtectProc )GetProcAddress( hKernel32, aszVirtualProtect );
            ENCODE_STR( Count, aszVirtualProtect );
        }
    }

    if ( IsDebuggerPresent == NULL )
    {
        if ( hKernel32 )
        {
            DECODE_STR( Count, aszIsDebuggerPresent );
            IsDebuggerPresent = ( IsDebuggerPresentProc )GetProcAddress( hKernel32, aszIsDebuggerPresent );
            ENCODE_STR( Count, aszIsDebuggerPresent );
        }
    }

#ifdef _MSC_VER
    __try
#endif
    {
        if ( CheckIfHook( ( UCHAR* )VirtualProtect, 16 ) )
            return TRUE;

        if ( CheckIfHook( ( UCHAR* )IsDebuggerPresent, 10 ) )
            return TRUE;

        if ( IsDebuggerPresent( ) )
            return TRUE;
    }
#ifdef _MSC_VER
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        return TRUE;
    }
#endif

    return FALSE;
}

void DestroyCode( PUCHAR AddressStart, PUCHAR AddressEnd )
{
    ULONG OldProtection;

    VirtualProtect( AddressStart, AddressEnd - AddressStart, PAGE_READWRITE, &OldProtection );
    memset( AddressStart, 0, AddressEnd - AddressStart );
    VirtualProtect( AddressStart, AddressEnd - AddressStart, OldProtection, &OldProtection );
}

void AlterCode( PUCHAR AddressStart, PUCHAR AddressEnd )
{
    ULONG OldProtection;

    VirtualProtect( AddressStart, AddressEnd - AddressStart, PAGE_READWRITE, &OldProtection );
    for ( ; AddressStart < AddressEnd; AddressStart++ )
        *AddressStart ^= 0xA5;
    VirtualProtect( AddressStart, AddressEnd - AddressStart, OldProtection, &OldProtection );
}

void EncodeDummyEnd( )
{
    /* Just for count */
    EncodeDummyStart( );
}

ULONG GetPeInfo(
    IN PVOID ModuleBase,
    OUT PIMAGE_NT_HEADERS *ppNH,
    OUT PIMAGE_FILE_HEADER *ppFH,
    OUT PIMAGE_OPTIONAL_HEADER *ppOH,
    OUT PIMAGE_SECTION_HEADER *ppSH
    )
{
    PIMAGE_DOS_HEADER DosHeader;
    PIMAGE_NT_HEADERS NtHeaders;
    PIMAGE_FILE_HEADER FileHeader;
    PIMAGE_OPTIONAL_HEADER OptionalHeader;
    PIMAGE_SECTION_HEADER SectionHeader;

#ifdef _MSC_VER
    __try
#endif
    {
        DosHeader = ( PIMAGE_DOS_HEADER )ModuleBase;
        if ( DosHeader->e_magic != IMAGE_DOS_SIGNATURE )
            return FALSE;

        NtHeaders = ( PIMAGE_NT_HEADERS ) ( ( UCHAR* )ModuleBase + DosHeader->e_lfanew );
        if ( NtHeaders->Signature != IMAGE_NT_SIGNATURE )
            return FALSE;

        FileHeader = ( PIMAGE_FILE_HEADER )&( NtHeaders )->FileHeader;
        OptionalHeader = ( PIMAGE_OPTIONAL_HEADER ) &( NtHeaders )->OptionalHeader;
        if ( ( OptionalHeader )->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC )
            return FALSE;

        SectionHeader = ( PIMAGE_SECTION_HEADER ) ( ( UCHAR* )OptionalHeader + sizeof( IMAGE_OPTIONAL_HEADER ) );
        if ( ppNH )
            *ppNH = NtHeaders;
        if ( ppFH )
            *ppFH = FileHeader;
        if ( ppOH )
            *ppOH = OptionalHeader;
        if ( ppSH )
            *ppSH = SectionHeader;
    }
#ifdef _MSC_VER
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        return FALSE;
    }
#endif

    return TRUE;
}

void RemoveCodeProtection( PVOID ModuleBase )
{
    ULONG Iter;
    ULONG Count;
    PIMAGE_FILE_HEADER FileHeader;
    PIMAGE_SECTION_HEADER SectionHeader;

    if ( GET_INTERNAL_STUB( )->Flags & ES_FLAGS_ENCODE )
    {
        if ( GetPeInfo( ModuleBase, NULL, &FileHeader, NULL, &SectionHeader ) )
        {
            for ( Iter = 0, Count = FileHeader->NumberOfSections; Iter < Count; Iter++, SectionHeader++ )
            {
                if ( SectionHeader->Characteristics & IMAGE_SCN_CNT_CODE )
                    VirtualProtect( ( UCHAR* )ModuleBase + SectionHeader->VirtualAddress, SectionHeader->SizeOfRawData, PAGE_READWRITE, &GET_INTERNAL_STUB( )->Protection );
            }
        }
        GET_INTERNAL_STUB( )->Flags |= ES_FLAGS_REMOVE_PROTECTION;
    }
}

void RecoverCodeProtection( PVOID ModuleBase )
{
    ULONG Iter;
    ULONG Count;
    PIMAGE_FILE_HEADER FileHeader;
    PIMAGE_SECTION_HEADER SectionHeader;

    if ( GET_INTERNAL_STUB( )->Flags & ES_FLAGS_REMOVE_PROTECTION )
    {
        if ( GetPeInfo( ModuleBase, NULL, &FileHeader, NULL, &SectionHeader ) )
        {
            for ( Iter = 0, Count = FileHeader->NumberOfSections; Iter < Count; Iter++, SectionHeader++ )
            {
                if ( SectionHeader->Characteristics & IMAGE_SCN_CNT_CODE )
                    VirtualProtect( ( UCHAR* )ModuleBase + SectionHeader->VirtualAddress, SectionHeader->SizeOfRawData, GET_INTERNAL_STUB( )->Protection, &GET_INTERNAL_STUB( )->Protection );
            }
        }
        GET_INTERNAL_STUB( )->Flags &= ~ES_FLAGS_REMOVE_PROTECTION;
    }
}

void EncodeKey( UCHAR *Key, ULONG KeyLength )
{
    UCHAR Prev;
    UCHAR *KeyPtr;
    UCHAR *KeyPtrEnd;

    Prev = 0;
    KeyPtr = Key;
    KeyPtrEnd = Key + KeyLength;
    while ( KeyPtr < KeyPtrEnd )
    {
        Prev = *KeyPtr = ( ( ( *KeyPtr ^ 0xAA ) + Prev ) ^ 0x55 ) + Prev;
        KeyPtr++;
    }
}

void DecodeKey( UCHAR *Key, ULONG KeyLength )
{
    UCHAR Prev;
    UCHAR *KeyPtr;
    UCHAR *KeyPtrStart;

    KeyPtr = Key + KeyLength;
    KeyPtrStart = Key;
    while ( KeyPtr > KeyPtrStart )
    {
        KeyPtr--;
        if ( KeyPtr == Key )
            Prev = 0;
        else
            Prev = *( KeyPtr - 1 );
        *KeyPtr = ( ( ( *KeyPtr - Prev ) ^ 0x55 ) - Prev ) ^ 0xAA;
    }
}

void ObfuscateKey( UCHAR *Key, ULONG KeyLength )
{
    UCHAR Prev;
    UCHAR Cur;
    UCHAR *KeyPtr;
    UCHAR *KeyPtrEnd;

    Prev = 0;
    KeyPtr = Key;
    KeyPtrEnd = Key + KeyLength;
    while ( KeyPtr < KeyPtrEnd )
    {
        Cur = *KeyPtr;
        *KeyPtr++ = ( ( ( Cur ^ 0xAA ) + Prev ) ^ 0x55 ) + Prev;
        Prev = Cur;
    }
}

void EncodeEx( UCHAR *Buffer, ULONG Length, UCHAR *Key, ULONG KeyLength )
{
    ULONG Iter;
    ULONG Count;
    UCHAR Prev;
    UCHAR *BufferPtr;
    UCHAR *KeyPtr;
    UCHAR *KeyPtrEnd;

    BufferPtr = Buffer;
    KeyPtrEnd = Key + KeyLength;
    for ( Iter = 0, Prev = 0, Count = Length / KeyLength; Iter < Count; Iter++ )
    {
        KeyPtr = Key;
        while ( KeyPtr < KeyPtrEnd )
        {
            Prev = *BufferPtr = ( ( ( *BufferPtr ^ *KeyPtr ) + Prev ) ^ ~*KeyPtr ) + Prev;
            BufferPtr++;
            KeyPtr++;
        }
    }

    KeyPtr = Key;
    KeyPtrEnd = Key + ( Length % KeyLength );
    while ( KeyPtr < KeyPtrEnd )
    {
        Prev = *BufferPtr = ( ( ( *BufferPtr ^ *KeyPtr ) + Prev ) ^ ~*KeyPtr ) + Prev;
        BufferPtr++;
        KeyPtr++;
    }
}

void DecodeEx( UCHAR *Buffer, ULONG Length, UCHAR *Key, ULONG KeyLength )
{
    ULONG Iter;
    ULONG Count;
    UCHAR Prev;
    UCHAR *BufferPtr;
    UCHAR *KeyPtr;
    UCHAR *KeyPtrStart;

    BufferPtr = Buffer + Length;
    KeyPtr = Key + ( Length % KeyLength );
    KeyPtrStart = Key;
    while ( KeyPtr > KeyPtrStart )
    {
        KeyPtr--;
        BufferPtr--;
        if ( BufferPtr == Buffer )
            Prev = 0;
        else
            Prev = *( BufferPtr - 1 );
        *BufferPtr = ( ( ( *BufferPtr - Prev ) ^ ~*KeyPtr ) - Prev ) ^ *KeyPtr;
    }

    for ( Iter = 0, Count = Length / KeyLength; Iter < Count; Iter++ )
    {
        KeyPtr = Key + KeyLength;
        while ( KeyPtr > KeyPtrStart )
        {
            KeyPtr--;
            BufferPtr--;
            if ( BufferPtr == Buffer )
                Prev = 0;
            else
                Prev = *( BufferPtr - 1 );
            *BufferPtr = ( ( ( *BufferPtr - Prev ) ^ ~*KeyPtr ) - Prev ) ^ *KeyPtr;
        }
    }
}

void EncodeInternalStub( PENCODE_STUB Stub, PVOID ImageBase, PVOID FileImage )
{
    ULONG Iter;
    ULONG Count;
    ULONG Length;
    UCHAR *StartAddress;
    UCHAR *Key;
    ULONG KeyLength;
    PENCODE_RANGE Range;

    if ( !( Stub->Flags & ES_FLAGS_ENCODE ) )
    {
        Range = ( PENCODE_RANGE ) ( ( PUCHAR )Stub->Range - ( PUCHAR )ImageBase + ( PUCHAR )FileImage );
        Key = Stub->InternalKey;
        KeyLength = Stub->InternalKeyLength;
        for ( Iter = 0, Count = Stub->Count; Iter < Count; Iter++, Range++ )
        {
            StartAddress = ( PUCHAR )Range->Start;
            Length = ( ( PUCHAR )Range->End - StartAddress ) & ~0xF;
            StartAddress += ( PUCHAR )FileImage - ( PUCHAR )ImageBase;
            EncodeEx( StartAddress, Length, Key, KeyLength );
        }
        EncodeKey( Key, KeyLength );
        Stub->Flags |= ES_FLAGS_ENCODE;
    }
}

void DecodeInternalStub( PENCODE_STUB Stub )
{
    ULONG Iter;
    ULONG Count;
    ULONG Length;
    UCHAR *StartAddress;
    UCHAR *Key;
    ULONG KeyLength;
    PENCODE_RANGE Range;

    if ( Stub == NULL )
        Stub = GET_INTERNAL_STUB( );

    if ( Stub->Flags & ES_FLAGS_ENCODE )
    {
        Key = Stub->InternalKey;
        KeyLength = Stub->InternalKeyLength;
        DecodeKey( Key, KeyLength );
        for ( Iter = 0, Count = Stub->Count; Iter < Count; Iter++ )
        {
            Range = &Stub->Range[Iter];
            StartAddress = ( PUCHAR )Range->Start;
            Length = ( ( PUCHAR )Range->End - StartAddress ) & ~0xF;
            DecodeEx( StartAddress, Length, Key, KeyLength );
        }
        Stub->Flags &= ~ES_FLAGS_ENCODE;
    }
}

void EncodeStub( PENCODE_STUB Stub, PVOID ImageBase, PVOID FileImage )
{
    ULONG Iter;
    ULONG Count;
    ULONG Length;
    UCHAR *StartAddress;
    UCHAR *Key;
    ULONG KeyLength;
    PENCODE_RANGE Range;

    if ( !( Stub->Flags & ES_FLAGS_ENCODE ) )
    {
        Range = ( PENCODE_RANGE ) ( ( PUCHAR )Stub->Range - ( PUCHAR )ImageBase + ( PUCHAR )FileImage );
        Key = Stub->Key;
        KeyLength = Stub->KeyLength;
        for ( Iter = 0, Count = Stub->Count; Iter < Count; Iter++, Range++ )
        {
            StartAddress = ( PUCHAR )Range->Start;
            Length = ( ( PUCHAR )Range->End - StartAddress ) & ~0xF;
            StartAddress += ( PUCHAR )FileImage - ( PUCHAR )ImageBase;
            if ( Range->Flags & ES_FLAGS_ENCODE_1 )
                DesCode( StartAddress, StartAddress, Length, Key, KeyLength, DES_ENCRYPT );
            else
                EncodeEx( StartAddress, Length, Key, KeyLength );
        }
        Stub->Flags |= ES_FLAGS_ENCODE;
    }
}

void DecodeStub( PENCODE_STUB Stub )
{
    ULONG Iter;
    ULONG Count;
    ULONG Length;
    UCHAR *StartAddress;
    UCHAR *Key;
    ULONG KeyLength;
    PENCODE_RANGE Range;

    if ( Stub->Flags & ES_FLAGS_ENCODE )
    {
        Key = Stub->Key;
        KeyLength = Stub->KeyLength;
        for ( Iter = 0, Count = Stub->Count; Iter < Count; Iter++ )
        {
            Range = &Stub->Range[Iter];
            StartAddress = ( PUCHAR )Range->Start;
            Length = ( ( PUCHAR )Range->End - StartAddress ) & ~0xF;
            if ( Range->Flags & ES_FLAGS_ENCODE_1 )
                DesCode( StartAddress, StartAddress, Length, Key, KeyLength, DES_DECRYPT );
            else
                DecodeEx( StartAddress, Length, Key, KeyLength );
        }
        Stub->Flags &= ~ES_FLAGS_ENCODE;
    }
}

, common/Hash.h

/*
///////////////////////////////////////////////////////////////////////////////
//
//  FileName    :   Hash.h
//  Version     :   1.0
//  Creator     :   RM
//  Create Date :   2006-01-01
//  Comment     :
//
///////////////////////////////////////////////////////////////////////////////
*/

#ifndef __HASH_H__
#define __HASH_H__

#ifdef __cplusplus
extern "C"
{
#endif

/*
///////////////////////////////////////////////////////////////////////////////
// D E F I N E S
///////////////////////////////////////////////////////////////////////////////
*/
#define HASH_KEY_IS_STRING 1
#define HASH_KEY_IS_LONG 2
#define HASH_KEY_NON_EXISTANT 3

#define HASH_UPDATE 1
#define HASH_ADD 2
#define HASH_NEXT_INSERT 4

#define HASH_DEL_KEY 0
#define HASH_DEL_INDEX 1

/* Flags */
#define HASH_FLAGS_PERSISTENT 1
#define HASH_FLAGS_PROTECTION 2

#define HASH_FLAGS_MASK 0xFF

/* Apply */
#define HASH_APPLY_KEEP 0
#define HASH_APPLY_REMOVE 1
#define HASH_APPLY_STOP 2

/* Function macro */
#define HashUpdate( Table, Key, KeyLength, Data, DataSize, Dest ) \
    HashAddOrUpdate( Table, Key, KeyLength, Data, DataSize, Dest, HASH_UPDATE )

#define HashAdd( Table, Key, KeyLength, Data, DataSize, Dest ) \
    HashAddOrUpdate( Table, Key, KeyLength, Data, DataSize, Dest, HASH_ADD )

#define HashQuickUpdate( Table, Key, KeyLength, h, Data, DataSize, Dest ) \
    HashQuickAddOrUpdate( Table, Key, KeyLength, h, Data, DataSize, Dest, HASH_UPDATE )

#define HashQuickAdd( Table, Key, KeyLength, h, Data, DataSize, Dest ) \
    HashQuickAddOrUpdate( Table, Key, KeyLength, h, Data, DataSize, Dest, HASH_ADD )

#define HashIndexUpdate( Table, h, Data, DataSize, Dest ) \
    HashIndexUpdateOrNextInsert( Table, h, Data, DataSize, Dest, HASH_UPDATE )

#define HashNextIndexInsert( Table, Data, DataSize, Dest ) \
    HashIndexUpdateOrNextInsert( Table, 0, Data, DataSize, Dest, HASH_NEXT_INSERT )

#define HashDelete( Table, Key, KeyLength ) \
    HashDeleteKeyOrIndex( Table, Key, KeyLength, 0, HASH_DEL_KEY )

#define HashIndexDelete( Table, h ) \
    HashDeleteKeyOrIndex( Table, NULL, 0, h, HASH_DEL_INDEX )

#define HashRemoveForward( Table ) \
    HashRemoveForwardEx( Table, NULL )
#define HashMoveBackward( Table ) \
    HashMoveBackwardEx( Table, NULL )
#define HashGetCurrentKey( Table, Key, Index, Flags ) \
    HashGetCurrentKeyEx( Table, Key, NULL, Index, Flags, NULL )
#define HashGetCurrentKeyType( Table ) \
    HashGetCurrentKeyTypeEx( Table, NULL )
#define HashGetCurrentData( Table, Data ) \
    HashGetCurrentDataEx( Table, Data, NULL )
#define HashInternalPointerReset( Table ) \
    HashInternalPointerResetEx( Table, NULL )
#define HashInternalPointerEnd( Table ) \
    HashInternalPointerEndEx( Table, NULL )

/*
///////////////////////////////////////////////////////////////////////////////
// S T R U C T U R E S
///////////////////////////////////////////////////////////////////////////////
*/
typedef ULONG ( *HASH_FUNCTION )( const TCHAR *Key, ULONG KeyLength );
typedef LONG ( *HASH_COMPARE_FUNCTION )( const void*, const void* );
typedef void ( *HASH_SORT_FUNCTION )( void*, ULONG, register ULONG, HASH_COMPARE_FUNCTION );
typedef void ( *HASH_DESTROY_FUNCTION )( void* );
typedef void ( *HASH_COPY_FUNCTION )( void *Element );

typedef struct _HASH_BUCKET {
    ULONG HashValue;
    ULONG KeyLength;
    void *Data;
    void *DataPtr;
    struct _HASH_BUCKET *ListNext;
    struct _HASH_BUCKET *ListLast;
    struct _HASH_BUCKET *Next;
    struct _HASH_BUCKET *Last;
    TCHAR Key[1]; /* Must be last element */
} HASH_BUCKET, *PHASH_BUCKET;

typedef struct _HASH_TABLE {
    ULONG TableSize;
    ULONG TableMask;
    ULONG NumOfElements;
    ULONG NextFreeElement;
    HASH_BUCKET *InternalPointer;
    HASH_BUCKET *ListHead;
    HASH_BUCKET *ListTail;
    HASH_BUCKET **Buckets;
    HASH_FUNCTION Hash;
    HASH_DESTROY_FUNCTION Destroy;
    UCHAR Flags;
    UCHAR ApplyCount;
    USHORT Reserved;
} HASH_TABLE, *PHASH_TABLE;

typedef struct _HASH_KEY {
    const TCHAR *Key;
    ULONG KeyLength;
    ULONG HashValue;
} HASH_KEY, *PHASH_KEY;

typedef struct _HASH_POINTER {
	HASH_BUCKET *Pos;
	ULONG HashValue;
} HASH_POINTER, *PHASH_POINTER;

typedef ULONG ( *APPLY_FUNCTION )( void *Dest );
typedef ULONG ( *APPLY_ARG_FUNCTION )( void *Dest, void *Context );
typedef ULONG ( *APPLY_ARGS_FUNCTION )( void *Dest, ULONG Count, va_list Args, HASH_KEY *HashKey );

typedef ULONG ( *MERGE_CALLBACK_FUNCTION )( void *Origin, void *New );
typedef ULONG ( *MERGE_CHECKER_FUNCTION ) ( HASH_TABLE*, void *SourceData, PHASH_KEY, void *Context );

/*
///////////////////////////////////////////////////////////////////////////////
// G L O B A L S
///////////////////////////////////////////////////////////////////////////////
*/

/*
///////////////////////////////////////////////////////////////////////////////
// F U N C T I O N S
///////////////////////////////////////////////////////////////////////////////
*/
ULONG DefaultHashFunction( const TCHAR *Key, ULONG KeyLength );
ULONG DefaultHashFunctionInline( const TCHAR *Key, ULONG KeyLength );

ULONG HashInit( HASH_TABLE*, ULONG Size, HASH_FUNCTION, HASH_DESTROY_FUNCTION, ULONG Flags );
ULONG HashInitEx( HASH_TABLE*, ULONG Size, HASH_FUNCTION, HASH_DESTROY_FUNCTION, ULONG Flags );
void HashDestroy( HASH_TABLE* );
void HashGracefulDestroy( HASH_TABLE* );
void HashGracefulReverseDestroy( HASH_TABLE* );
void HashClear( HASH_TABLE* );

ULONG HashAddOrUpdate( HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, void *Data, ULONG DataSize, void **Dest, ULONG Flags );
ULONG HashQuickAddOrUpdate( HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, void *Data, ULONG DataSize, void **Dest, ULONG Flags );
ULONG HashIndexUpdateOrNextInsert( HASH_TABLE*, ULONG HashValue, void *Data, ULONG DataSize, void **Dest, ULONG Flags );
ULONG HashAddEmptyElement( HASH_TABLE*, const TCHAR *Key, ULONG KeyLength );

void HashSetApplyProtection( PHASH_TABLE Table, ULONG Set );
void HashApply( HASH_TABLE*, APPLY_FUNCTION );
void HashApplyWithArgument( HASH_TABLE*, APPLY_ARG_FUNCTION, void* );
void HashApplyWithArgumentEx( HASH_TABLE*, APPLY_ARGS_FUNCTION, ULONG, ... );
void HashGracefulReverseApply( HASH_TABLE*, APPLY_FUNCTION );

ULONG HashDeleteKeyOrIndex( HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, ULONG Flags );

ULONG HashFind( const HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, void **Data );
ULONG HashQuickFind( const HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, void **Data );
ULONG HashIndexFind( const HASH_TABLE*, ULONG HashValue, void **Data );

ULONG HashIsExist( const HASH_TABLE*, const TCHAR *Key, ULONG KeyLength );
ULONG HashQuickIsExist( const HASH_TABLE*, const TCHAR *Key, ULONG KeyLength, ULONG HashValue );
ULONG HashIndexIsExist( const HASH_TABLE*, ULONG HashValue );

ULONG HashGetPointer( HASH_TABLE*, HASH_POINTER* );
ULONG HashSetPointer( HASH_TABLE*, const HASH_POINTER* );

void HashInternalPointerResetEx( HASH_TABLE*, PHASH_BUCKET* );
void HashInternalPointerEndEx( HASH_TABLE*, PHASH_BUCKET* );

ULONG HashRemoveForwardEx( HASH_TABLE*, PHASH_BUCKET* );
ULONG HashMoveBackwardEx( HASH_TABLE*, PHASH_BUCKET* );
ULONG HashGetCurrentKeyEx( HASH_TABLE*, TCHAR **Key, ULONG *KeyLength, ULONG *Index, ULONG Flags, PHASH_BUCKET* );
ULONG HashGetCurrentKeyTypeEx( HASH_TABLE*, PHASH_BUCKET* );
ULONG HashGetCurrentDataEx( HASH_TABLE*, void **Data, PHASH_BUCKET* );
ULONG HashUpdateCurrentKeyEx( HASH_TABLE *Table, ULONG KeyType, TCHAR *Key, ULONG KeyLength, ULONG Index, PHASH_BUCKET *Pos );

void HashCopy( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION, void *Buffer, ULONG Size );
void HashMerge( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION, void *Buffer, ULONG Size, ULONG Overwrite );
void HashMergeEx( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION, ULONG Size, MERGE_CHECKER_FUNCTION, void *Context );

ULONG HashSort( HASH_TABLE*, HASH_SORT_FUNCTION, HASH_COMPARE_FUNCTION, ULONG ReNumber );
ULONG HashCompare( HASH_TABLE*, HASH_TABLE*, HASH_COMPARE_FUNCTION, ULONG Ordered );
ULONG HashMinMax( HASH_TABLE*, HASH_COMPARE_FUNCTION, ULONG Flags, void **Data );

ULONG HashGetValue( const TCHAR *Key, ULONG KeyLength );
ULONG HashGetCount( const HASH_TABLE* );
ULONG HashGetNextFreeElement( const HASH_TABLE* );

ULONG HashRefresh( HASH_TABLE* );

#ifdef __cplusplus
}
#endif
/*
///////////////////////////////////////////////////////////////////////////////
// E N D  O F  F I L E
///////////////////////////////////////////////////////////////////////////////
*/
#endif /* __HASH_H__ */

, common/Hash.c

/*
///////////////////////////////////////////////////////////////////////////////
//
//  FileName    :   Hash.c
//  Version     :   1.0
//  Creator     :   RM
//  Create Date :   2006-01-01
//  Comment     :
//
///////////////////////////////////////////////////////////////////////////////
*/

#include < tchar.h >
#include < stdio.h >
#include < stdarg.h >
#include < malloc.h >

#ifdef _MSC_VER
#include < windows.h >
#else
#include "Compatible.h"
#endif

#include "AddLog.h"
#include "Hash.h"

#pragma warning( disable : 4706 )

/*
///////////////////////////////////////////////////////////////////////////////
// D E F I N E S
///////////////////////////////////////////////////////////////////////////////
*/
#ifndef HEAP_ALLOC
#define HEAP_ALLOC( Size ) HeapAlloc( GetProcessHeap( ), 0, Size )
#endif

#ifndef HEAP_FREE
#define HEAP_FREE( Buffer ) HeapFree( GetProcessHeap( ), 0, Buffer )
#endif

#ifndef HEAP_REALLOC
#define HEAP_REALLOC( Buffer, Size ) HeapReAlloc( GetProcessHeap( ), 0, Buffer, Size )
#endif

#define HANDLE_BLOCK_INTERRUPTIONS( )
#define HANDLE_UNBLOCK_INTERRUPTIONS( )

#define HANDLE_NUMERIC( Key, Length, Func ) { \
    register const TCHAR *Tmp = Key; \
    if ( *Tmp == _T( '-' ) ) { \
        Tmp++; \
    } \
    if ( ( *Tmp >= _T( '0' ) && *Tmp <= _T( '9' ) ) ) do { /* Possibly numeric index */ \
        const TCHAR *End = Key + Length - 1; \
        ULONG Index; \
        if ( *Tmp++ == _T( '0' ) && Length > 2 ) { /* Don't accept numbers with leading zeros */ \
            break; \
        } \
        while ( Tmp < End ) { \
            if ( !( *Tmp >= _T( '0' ) && *Tmp <= _T( '9' ) ) ) { \
                break; \
            } \
            Tmp++; \
        } \
        if ( Tmp == End && *Tmp == _T( '\0' ) ) { /* Numeric index */ \
            if ( *Key == _T( '-' ) ) { \
                Index = _tcstol( Key, NULL, 10 ); \
                if ( Index != LONG_MIN ) { \
                    return Func; \
                } \
            } else { \
                Index = _tcstol( Key, NULL, 10 ); \
                if ( Index != LONG_MAX ) { \
                    return Func; \
                } \
            } \
        } \
    } while ( 0 ); \
}

#define CONNECT_TO_BUCKET_LIST( Element, ListHead ) \
    ( Element )->Next = ( ListHead ); \
    ( Element )->Last = NULL; \
    if ( ( Element )->Next ) { \
        ( Element )->Next->Last = ( Element ); \
    }

#define CONNECT_TO_GLOBAL_LIST( Element, Table ) \
    ( Element )->ListLast = ( Table )->ListTail; \
    ( Table )->ListTail = ( Element ); \
    ( Element )->ListNext = NULL; \
    if ( ( Element )->ListLast != NULL ) { \
        ( Element )->ListLast->ListNext = ( Element ); \
    } \
    if ( !( Table )->ListHead ) { \
        ( Table )->ListHead = ( Element ); \
    } \
    if ( ( Table )->InternalPointer == NULL ) { \
        ( Table )->InternalPointer = ( Element ); \
    }

#define HASH_PROTECT_RECURSION( Table ) \
    if ( ( Table )->Flags & HASH_FLAGS_PROTECTION ) { \
        if ( ( Table )->ApplyCount++ >= 3 ) { \
            ADD_LOGA( "Nesting level too deep - recursive dependency?" ); \
        } \
    }

#define HASH_UNPROTECT_RECURSION( Table ) \
    if ( ( Table )->Flags & HASH_FLAGS_PROTECTION ) { \
        ( Table )->ApplyCount--; \
    }

#define HASH_IF_FULL_DO_RESIZE( Table ) \
    if ( ( Table )->NumOfElements > ( Table )->TableSize ) { \
        HashDoResize( Table ); \
    }

#define UPDATE_DATA( Table, Bucket, Data, DataSize ) \
    if ( DataSize == sizeof( void* ) ) { \
        if ( !( Bucket )->DataPtr ) { \
            HEAP_FREE( ( Bucket )->Data ); \
        } \
        memcpy( &( Bucket )->DataPtr, Data, sizeof( void* ) ); \
        ( Bucket )->Data = &( Bucket )->DataPtr; \
    } else { \
        if ( ( Bucket )->Data == &( Bucket )->DataPtr ) { \
            ( Bucket )->Data = ( void* )HEAP_ALLOC( DataSize ); \
            ( Bucket )->DataPtr = NULL; \
        } else { \
            ( Bucket )->Data = ( void* )HEAP_REALLOC( ( Bucket )->Data, DataSize ); \
        } \
        memcpy( ( Bucket )->Data, Data, DataSize ); \
    }

#define INIT_DATA( Table, Bucket, Data, DataSize ); \
    if ( DataSize == sizeof( void* ) ) { \
        memcpy( &( Bucket )->DataPtr, Data, sizeof( void* ) ); \
        ( Bucket )->Data = &( Bucket )->DataPtr; \
    } else { \
        ( Bucket )->Data = ( void* )HEAP_ALLOC( DataSize ); \
        if ( !( Bucket )->Data ) { \
            HEAP_FREE( Bucket ); \
            return FALSE; \
        } \
        memcpy( ( Bucket )->Data, Data, DataSize ); \
        ( Bucket )->DataPtr = NULL; \
    }

/*
///////////////////////////////////////////////////////////////////////////////
// S T R U C T U R E S
///////////////////////////////////////////////////////////////////////////////
*/

/*
///////////////////////////////////////////////////////////////////////////////
// G L O B A L S
///////////////////////////////////////////////////////////////////////////////
*/

/*
///////////////////////////////////////////////////////////////////////////////
// F U N C T I O N S
///////////////////////////////////////////////////////////////////////////////
*/
/*
 * DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
 *
 * This is Daniel J. Bernstein's popular `times 33' hash function as
 * posted by him years ago on comp.lang.c. It basically uses a function
 * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
 * known hash functions for strings. Because it is both computed very
 * fast and distributes very well.
 *
 * The magic of number 33, i.e. why it works better than many other
 * constants, prime or not, has never been adequately explained by
 * anyone. So I try an explanation: if one experimentally tests all
 * multipliers between 1 and 256 (as RSE did now) one detects that even
 * numbers are not usable at all. The remaining 128 odd numbers
 * (except for the number 1) work more or less all equally well. They
 * all distribute in an acceptable way and this way fill a hash table
 * with an average percent of approx. 86%. 
 *
 * If one compares the Chi^2 values of the variants, the number 33 not
 * even has the best value. But the number 33 and a few other equally
 * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
 * advantage to the remaining numbers in the large set of possible
 * multipliers: their multiply operation can be replaced by a faster
 * operation based on just one shift plus either a single addition
 * or subtraction operation. And because a hash function has to both
 * distribute good _and_ has to be very fast to compute, those few
 * numbers should be preferred and seems to be the reason why Daniel J.
 * Bernstein also preferred it.
 */
__inline ULONG DefaultHashFunctionInline( const TCHAR *Key, ULONG KeyLength )
{
    register ULONG HashValue = 5381;

    for ( ; KeyLength >= 8; KeyLength -= 8 )
    {
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
    }
    switch ( KeyLength )
    {
        case 7: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 6: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 5: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 4: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 3: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 2: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++;
        case 1: HashValue = ( ( HashValue << 5 ) + HashValue ) + *Key++; break;
        case 0: break;
    }

    return HashValue;
}

ULONG DefaultHashFunction( const TCHAR *Key, ULONG KeyLength )
{
    return DefaultHashFunctionInline( Key, KeyLength );
}

static HASH_BUCKET* HashApplyDeleter( HASH_TABLE *Table, HASH_BUCKET *Bucket )
{
    ULONG Index;
    HASH_BUCKET *RetCode;

    HANDLE_BLOCK_INTERRUPTIONS( );
    if ( Bucket->Last )
    {
        Bucket->Last->Next = Bucket->Next;
    }
    else
    {
        Index = Bucket->HashValue & Table->TableMask;
        Table->Buckets[Index] = Bucket->Next;
    }

    if ( Bucket->Next )
    {
        Bucket->Next->Last = Bucket->Last;
    }
    else
    {
        /* Nothing to do as this list doesn't have a tail */
    }

    if ( Bucket->ListLast != NULL )
        Bucket->ListLast->ListNext = Bucket->ListNext;
    else
        Table->ListHead = Bucket->ListNext;

    if ( Bucket->ListNext != NULL )
        Bucket->ListNext->ListLast = Bucket->ListLast;
    else
        Table->ListTail = Bucket->ListLast;

    if ( Table->InternalPointer == Bucket )
        Table->InternalPointer = Bucket->ListNext;

    Table->NumOfElements--;
    HANDLE_UNBLOCK_INTERRUPTIONS( );

    if ( Table->Destroy )
        Table->Destroy( Bucket->Data );

    if ( Bucket->Data != &Bucket->DataPtr )
        HEAP_FREE( Bucket->Data );

    RetCode = Bucket->ListNext;
    HEAP_FREE( Bucket );

    return RetCode;
}

static ULONG HashDoResize( HASH_TABLE *Table )
{
    HASH_BUCKET **Buckets;

    if ( ( Table->TableSize << 1 ) > 0 )
    {
        Buckets = ( HASH_BUCKET** )HEAP_REALLOC( Table->Buckets, ( Table->TableSize << 1 ) * sizeof( HASH_BUCKET* ) );
        if ( Buckets == NULL )
        {
            Buckets = ( HASH_BUCKET** )HEAP_ALLOC( ( Table->TableSize << 1 ) * sizeof( HASH_BUCKET* ) );
            if ( Buckets == NULL )
                return FALSE;
        }
        HANDLE_BLOCK_INTERRUPTIONS( );
        Table->Buckets = Buckets;
        Table->TableSize = ( Table->TableSize << 1 );
        Table->TableMask = Table->TableSize - 1;
        HashRefresh( Table );
        HANDLE_UNBLOCK_INTERRUPTIONS( );
        return TRUE;
    }

    return TRUE;
}

static ULONG HashReplaceCheckerWrapper( HASH_TABLE *Target, void *Data, HASH_BUCKET *Bucket, void *Context, MERGE_CHECKER_FUNCTION MergeCheckerFunction )
{
    HASH_KEY HashKey;

    HashKey.Key = Bucket->Key;
    HashKey.KeyLength = Bucket->KeyLength;
    HashKey.HashValue = Bucket->HashValue;

    return MergeCheckerFunction( Target, Data, &HashKey, Context );
}

ULONG HashInitEx( PHASH_TABLE Table, ULONG Size, HASH_FUNCTION HashFunction, HASH_DESTROY_FUNCTION DestroyFunction, ULONG Flags )
{
    ULONG Iter;
    HASH_BUCKET **Buckets;

    Iter = 3;
    if ( Size >= 0x80000000 )
    {
        /* Prevent overflow */
        Table->TableSize = 0x80000000;
    }
    else
    {
        while ( ( 1U << Iter ) < Size )
            Iter++;
        Table->TableSize = 1 << Iter;
    }

    if ( HashFunction == NULL )
        HashFunction = DefaultHashFunction;

    Table->TableMask = Table->TableSize - 1;
    Table->Hash = HashFunction;
    Table->Destroy = DestroyFunction;
    Table->Buckets = NULL;
    Table->ListHead = NULL;
    Table->ListTail = NULL;
    Table->NumOfElements = 0;
    Table->NextFreeElement = 0;
    Table->InternalPointer = NULL;
    Table->Flags = ( UCHAR )Flags;
    Table->ApplyCount = 0;
    Table->Reserved = 0;

    Buckets = ( HASH_BUCKET** )HEAP_ALLOC( Table->TableSize * sizeof( HASH_BUCKET* ) );
    if ( Buckets == NULL )
        return FALSE;

    memset( Buckets, 0, Table->TableSize * sizeof( HASH_BUCKET* ) );
    Table->Buckets = Buckets;

    return TRUE;
}

ULONG HashInit( PHASH_TABLE Table, ULONG Size, HASH_FUNCTION HashFunction, HASH_DESTROY_FUNCTION DestroyFunction, ULONG Flags )
{
    return HashInitEx( Table, Size, HashFunction, DestroyFunction, Flags | HASH_FLAGS_PROTECTION );
}

void HashDestroy( PHASH_TABLE Table )
{
    HASH_BUCKET *Cur, *Prev;

    Cur = Table->ListHead;
    while ( Cur != NULL )
    {
        Prev = Cur;
        Cur = Cur->ListNext;
        if ( Table->Destroy )
            Table->Destroy( Prev->Data );
        if ( Prev->Data != &Prev->DataPtr )
            HEAP_FREE( Prev->Data );
        HEAP_FREE( Prev );
    }
    HEAP_FREE( Table->Buckets );
}

void HashGracefulDestroy( HASH_TABLE *Table )
{
    HASH_BUCKET *Bucket;

    Bucket = Table->ListHead;
    while ( Bucket != NULL )
        Bucket = HashApplyDeleter( Table, Bucket );
    HEAP_FREE( Table->Buckets );
}

void HashGracefulReverseDestroy( HASH_TABLE *Table )
{
    HASH_BUCKET *Bucket;

    Bucket = Table->ListTail;
    while ( Bucket != NULL )
    {
        HashApplyDeleter( Table, Bucket );
        Bucket = Table->ListTail;
    }
    HEAP_FREE( Table->Buckets );
}

void HashClear( PHASH_TABLE Table )
{
    HASH_BUCKET *Cur, *Prev;

    Cur = Table->ListHead;
    while ( Cur != NULL )
    {
        Prev = Cur;
        Cur = Cur->ListNext;
        if ( Table->Destroy )
            Table->Destroy( Prev->Data );
        if ( Prev->Data != &Prev->DataPtr )
            HEAP_FREE( Prev->Data );
        HEAP_FREE( Prev );
    }
    memset( Table->Buckets, 0, Table->TableSize * sizeof( HASH_BUCKET* ) );
    Table->ListHead = NULL;
    Table->ListTail = NULL;
    Table->NumOfElements = 0;
    Table->NextFreeElement = 0;
    Table->InternalPointer = NULL;
}

ULONG HashAddOrUpdate( PHASH_TABLE Table, const TCHAR *Key, ULONG KeyLength, void *Data, ULONG DataSize, void **Dest, ULONG Flags )
{
    ULONG HashValue;
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( KeyLength <= 0 )
        return FALSE;

    HashValue = Table->Hash( Key, KeyLength );
    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
            {
                if ( Flags & HASH_ADD )
                    return FALSE;

                HANDLE_BLOCK_INTERRUPTIONS( );
                if ( Table->Destroy )
                    Table->Destroy( Bucket->Data );
                UPDATE_DATA( Table, Bucket, Data, DataSize );
                if ( Dest )
                    *Dest = Bucket->Data;
                HANDLE_UNBLOCK_INTERRUPTIONS( );
                return TRUE;
            }
        }
        Bucket = Bucket->Next;
    }

    Bucket = ( HASH_BUCKET* )HEAP_ALLOC( sizeof( HASH_BUCKET ) + ( KeyLength - 1 ) * sizeof( TCHAR ) );
    if ( Bucket == NULL )
        return FALSE;

    memcpy( Bucket->Key, Key, KeyLength );
    Bucket->KeyLength = KeyLength;
    INIT_DATA( Table, Bucket, Data, DataSize );
    Bucket->HashValue = HashValue;
    CONNECT_TO_BUCKET_LIST( Bucket, Table->Buckets[Index] );
    if ( Dest )
        *Dest = Bucket->Data;

    HANDLE_BLOCK_INTERRUPTIONS( );
    CONNECT_TO_GLOBAL_LIST( Bucket, Table );
    Table->Buckets[Index] = Bucket;
    HANDLE_UNBLOCK_INTERRUPTIONS( );

    Table->NumOfElements++;
    HASH_IF_FULL_DO_RESIZE( Table );

    return TRUE;
}

ULONG HashQuickAddOrUpdate( HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, void *Data, ULONG DataSize, void **Dest, ULONG Flags )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( KeyLength == 0 )
        return HashIndexUpdate( Table, HashValue, Data, DataSize, Dest );

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
            {
                if ( Flags & HASH_ADD )
                    return FALSE;

                HANDLE_BLOCK_INTERRUPTIONS( );
                if ( Table->Destroy )
                    Table->Destroy( Bucket->Data );
                UPDATE_DATA( Table, Bucket, Data, DataSize );
                if ( Dest )
                    *Dest = Bucket->Data;
                HANDLE_UNBLOCK_INTERRUPTIONS( );
                return TRUE;
            }
        }
        Bucket = Bucket->Next;
    }

    Bucket = ( HASH_BUCKET* )HEAP_ALLOC( sizeof( HASH_BUCKET ) + ( KeyLength - 1 ) * sizeof( TCHAR ) );
    if ( Bucket == NULL )
        return FALSE;

    memcpy( Bucket->Key, Key, KeyLength );
    Bucket->KeyLength = KeyLength;
    INIT_DATA( Table, Bucket, Data, DataSize );
    Bucket->HashValue = HashValue;
    CONNECT_TO_BUCKET_LIST( Bucket, Table->Buckets[Index] );
    if ( Dest )
        *Dest = Bucket->Data;

    HANDLE_BLOCK_INTERRUPTIONS( );
    Table->Buckets[Index] = Bucket;
    CONNECT_TO_GLOBAL_LIST( Bucket, Table );
    HANDLE_UNBLOCK_INTERRUPTIONS( );

    Table->NumOfElements++;
    HASH_IF_FULL_DO_RESIZE( Table );

    return TRUE;
}

ULONG HashIndexUpdateOrNextInsert( HASH_TABLE *Table, ULONG HashValue, void *Data, ULONG DataSize, void **Dest, ULONG Flags )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( Flags & HASH_NEXT_INSERT )
        HashValue = Table->NextFreeElement;

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->KeyLength == 0 ) && ( Bucket->HashValue == HashValue ) )
        {
            if ( Flags & HASH_NEXT_INSERT || Flags & HASH_ADD )
                return FALSE;

            HANDLE_BLOCK_INTERRUPTIONS( );
            if ( Table->Destroy )
                Table->Destroy( Bucket->Data );
            UPDATE_DATA( Table, Bucket, Data, DataSize );
            if ( ( LONG )HashValue >= ( LONG )Table->NextFreeElement )
                Table->NextFreeElement = HashValue + 1;
            if ( Dest )
                *Dest = Bucket->Data;
            HANDLE_UNBLOCK_INTERRUPTIONS( );
            return TRUE;
        }
        Bucket = Bucket->Next;
    }

    Bucket = ( HASH_BUCKET* )HEAP_ALLOC( sizeof( HASH_BUCKET ) - 1 * sizeof( TCHAR ) );
    if ( Bucket == NULL )
        return FALSE;

    Bucket->KeyLength = 0; /* Numeric are marked by making the KeyLength == 0 */
    INIT_DATA( Table, Bucket, Data, DataSize );
    Bucket->HashValue = HashValue;
    CONNECT_TO_BUCKET_LIST( Bucket, Table->Buckets[Index] );
    if ( Dest )
        *Dest = Bucket->Data;

    HANDLE_BLOCK_INTERRUPTIONS( );
    Table->Buckets[Index] = Bucket;
    CONNECT_TO_GLOBAL_LIST( Bucket, Table );
    HANDLE_UNBLOCK_INTERRUPTIONS( );

    if ( ( LONG )HashValue >= ( LONG )Table->NextFreeElement )
        Table->NextFreeElement = HashValue + 1;

    Table->NumOfElements++;
    HASH_IF_FULL_DO_RESIZE( Table );

    return TRUE;
}

ULONG HashAddEmptyElement( HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength )
{
    void *Dummy = ( void* )1;
    return HashAdd( Table, Key, KeyLength, &Dummy, sizeof( void* ), NULL );
}

void HashSetApplyProtection( PHASH_TABLE Table, ULONG Set )
{
    if ( Set )
        Table->Flags |= HASH_FLAGS_PROTECTION;
    else
        Table->Flags &= ~HASH_FLAGS_PROTECTION;
}

void HashApply( HASH_TABLE *Table, APPLY_FUNCTION ApplyFunction )
{
    ULONG RetCode;
    HASH_BUCKET *Bucket;

    HASH_PROTECT_RECURSION( Table );
    Bucket = Table->ListHead;
    while ( Bucket != NULL )
    {
        RetCode = ApplyFunction( Bucket->Data );
        if ( RetCode & HASH_APPLY_REMOVE )
            Bucket = HashApplyDeleter( Table, Bucket );
        else
            Bucket = Bucket->ListNext;

        if ( RetCode & HASH_APPLY_STOP )
            break;
    }
    HASH_UNPROTECT_RECURSION( Table );
}

void HashApplyWithArgument( HASH_TABLE *Table, APPLY_ARG_FUNCTION ApplyFunction, void *Context )
{
    ULONG RetCode;
    HASH_BUCKET *Bucket;

    HASH_PROTECT_RECURSION( Table );
    Bucket = Table->ListHead;
    while ( Bucket != NULL )
    {
        RetCode = ApplyFunction( Bucket->Data, Context );
        if ( RetCode & HASH_APPLY_REMOVE )
            Bucket = HashApplyDeleter( Table, Bucket );
        else
            Bucket = Bucket->ListNext;

        if ( RetCode & HASH_APPLY_STOP )
            break;
    }
    HASH_UNPROTECT_RECURSION( Table );
}

void HashApplyWithArgumentEx( HASH_TABLE *Table, APPLY_ARGS_FUNCTION ApplyFunction, ULONG Count, ... )
{
    ULONG RetCode;
    HASH_BUCKET *Bucket;
    va_list Args;
    HASH_KEY HashKey;

    Bucket = Table->ListHead;
    while ( Bucket != NULL )
    {
        va_start( Args, Count );
        HashKey.Key = Bucket->Key;
        HashKey.KeyLength = Bucket->KeyLength;
        HashKey.HashValue = Bucket->HashValue;
        RetCode = ApplyFunction( Bucket->Data, Count, Args, &HashKey );

        if ( RetCode & HASH_APPLY_REMOVE )
            Bucket = HashApplyDeleter( Table, Bucket );
        else
            Bucket = Bucket->ListNext;

        if ( RetCode & HASH_APPLY_STOP )
            break;
        va_end( Args );
    }
    HASH_UNPROTECT_RECURSION( Table );
}

void HashGracefulReverseApply( HASH_TABLE *Table, APPLY_FUNCTION ApplyFunction )
{
    ULONG RetCode;
    HASH_BUCKET *Bucket;
    HASH_BUCKET *Prev;

    HASH_PROTECT_RECURSION( Table );
    Bucket = Table->ListTail;
    while ( Bucket != NULL )
    {
        RetCode = ApplyFunction( Bucket->Data );
        Prev = Bucket;
        Bucket = Bucket->ListLast;
        if ( RetCode & HASH_APPLY_REMOVE )
            HashApplyDeleter( Table, Prev );

        if ( RetCode & HASH_APPLY_STOP )
            break;
    }
    HASH_UNPROTECT_RECURSION( Table );
}

ULONG HashDeleteKeyOrIndex( HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, ULONG Flags )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( Flags == HASH_DEL_KEY )
        HashValue = Table->Hash( Key, KeyLength );

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) && ( ( Bucket->KeyLength == 0 ) || !memcmp( Bucket->Key, Key, KeyLength ) ) )
        {
            HANDLE_BLOCK_INTERRUPTIONS( );
            if ( Bucket == Table->Buckets[Index] )
                Table->Buckets[Index] = Bucket->Next;
            else
                Bucket->Last->Next = Bucket->Next;

            if ( Bucket->Next )
                Bucket->Next->Last = Bucket->Last;

            if ( Bucket->ListLast != NULL )
                Bucket->ListLast->ListNext = Bucket->ListNext;
            else
                Table->ListHead = Bucket->ListNext;

            if ( Bucket->ListNext != NULL )
                Bucket->ListNext->ListLast = Bucket->ListLast;
            else
                Table->ListTail = Bucket->ListLast;

            if ( Table->InternalPointer == Bucket )
                Table->InternalPointer = Bucket->ListNext;

            if ( Table->Destroy )
                Table->Destroy( Bucket->Data );

            if ( Bucket->Data != &Bucket->DataPtr )
                HEAP_FREE( Bucket->Data );

            HEAP_FREE( Bucket );
            HANDLE_UNBLOCK_INTERRUPTIONS( );
            Table->NumOfElements--;
            return TRUE;
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashFind( const HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength, void **Data )
{
    ULONG HashValue;
    ULONG Index;
    HASH_BUCKET *Bucket;

    HashValue = Table->Hash( Key, KeyLength );
    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
            {
                *Data = Bucket->Data;
                return TRUE;
            }
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashQuickFind( const HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength, ULONG HashValue, void **Data )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( KeyLength == 0 )
        return HashIndexFind( Table, HashValue, Data );

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
            {
                *Data = Bucket->Data;
                return TRUE;
            }
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashIndexFind( const HASH_TABLE *Table, ULONG HashValue, void **Data )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == 0 ) )
        {
            *Data = Bucket->Data;
            return TRUE;
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashIsExist( const HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength )
{
    ULONG HashValue;
    ULONG Index;
    HASH_BUCKET *Bucket;

    HashValue = Table->Hash( Key, KeyLength );
    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
                return TRUE;
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashQuickIsExist( const HASH_TABLE *Table, const TCHAR *Key, ULONG KeyLength, ULONG HashValue )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    if ( KeyLength == 0 )
        return HashIndexIsExist( Table, HashValue );

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == KeyLength ) )
        {
            if ( !memcmp( Bucket->Key, Key, KeyLength ) )
                return TRUE;
        }
        Bucket = Bucket->Next;
    }

    return FALSE;
}

ULONG HashIndexIsExist( const HASH_TABLE *Table, ULONG HashValue )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    Index = HashValue & Table->TableMask;
    Bucket = Table->Buckets[Index];
    while ( Bucket != NULL )
    {
        if ( ( Bucket->HashValue == HashValue ) && ( Bucket->KeyLength == 0 ) )
            return TRUE;
        Bucket = Bucket->Next;
    }

    return 0;
}

ULONG HashGetPointer( HASH_TABLE *Table, HASH_POINTER *HashPointer )
{
    HashPointer->Pos = Table->InternalPointer;
    if ( Table->InternalPointer )
    {
        HashPointer->HashValue = Table->InternalPointer->HashValue;
        return TRUE;
    }
    else
    {
        HashPointer->HashValue = 0;
        return FALSE;
    }
}

ULONG HashSetPointer( HASH_TABLE *Table, const HASH_POINTER *HashPointer )
{
    HASH_BUCKET *Bucket;

    if ( Table->InternalPointer != HashPointer->Pos )
    {
        Bucket = Table->Buckets[HashPointer->HashValue & Table->TableMask];
        while ( Bucket != NULL )
        {
            if ( Bucket == HashPointer->Pos )
            {
                Table->InternalPointer = Bucket;
                return TRUE;
            }
            Bucket = Bucket->Next;
        }
        return FALSE;
    }

    return TRUE;
}

void HashInternalPointerResetEx( HASH_TABLE *Table, PHASH_BUCKET *Pos )
{
    if ( Pos )
        *Pos = Table->ListHead;
    else
        Table->InternalPointer = Table->ListHead;
}

void HashInternalPointerEndEx( HASH_TABLE *Table, PHASH_BUCKET *Pos )
{
    if ( Pos )
        *Pos = Table->ListTail;
    else
        Table->InternalPointer = Table->ListTail;
}

ULONG HashRemoveForwardEx( HASH_TABLE *Table, PHASH_BUCKET *Pos )
{
    PHASH_BUCKET *Cur;

    Cur = Pos ? Pos : &Table->InternalPointer;
    if ( *Cur )
    {
        *Cur = ( *Cur )->ListNext;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG HashMoveBackwardEx( HASH_TABLE *Table, PHASH_BUCKET *Pos )
{
    PHASH_BUCKET *Cur;

    Cur = Pos ? Pos : &Table->InternalPointer;
    if ( *Cur )
    {
        *Cur = ( *Cur )->ListLast;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG HashGetCurrentKeyEx( HASH_TABLE *Table, TCHAR **Key, ULONG *KeyLength, ULONG *Index, ULONG Duplicate, PHASH_BUCKET *Pos )
{
    HASH_BUCKET *Bucket;

    Bucket = Pos ? ( *Pos ) : Table->InternalPointer;
    if ( Bucket )
    {
        if ( Bucket->KeyLength )
        {
            if ( Duplicate )
            {
                *Key = ( TCHAR* )HEAP_ALLOC( Bucket->KeyLength * sizeof( TCHAR ) );
                if ( *Key )
                {
                    memcpy( *Key, Bucket->Key, ( Bucket->KeyLength - 1 ) * sizeof( TCHAR ) );
                    *( *Key ) = _T( '\0' );
                }
            }
            else
            {
                *Key = Bucket->Key;
            }
            if ( KeyLength )
                *KeyLength = Bucket->KeyLength;
            return HASH_KEY_IS_STRING;
        }
        else
        {
            *Index = Bucket->HashValue;
            return HASH_KEY_IS_LONG;
        }
    }

    return HASH_KEY_NON_EXISTANT;
}

ULONG HashGetCurrentKeyTypeEx( HASH_TABLE *Table, PHASH_BUCKET *Pos )
{
    HASH_BUCKET *Bucket;

    Bucket = Pos ? ( *Pos ) : Table->InternalPointer;
    if ( Bucket )
    {
        if ( Bucket->KeyLength )
            return HASH_KEY_IS_STRING;
        else
            return HASH_KEY_IS_LONG;
    }

    return HASH_KEY_NON_EXISTANT;
}

ULONG HashGetCurrentDataEx( HASH_TABLE *Table, void **Data, PHASH_BUCKET *Pos )
{
    HASH_BUCKET *Bucket;

    Bucket = Pos ? ( *Pos ) : Table->InternalPointer;
    if ( Bucket )
    {
        *Data = Bucket->Data;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ULONG HashUpdateCurrentKeyEx( HASH_TABLE *Table, ULONG KeyType, TCHAR *Key, ULONG KeyLength, ULONG Index, PHASH_BUCKET *Pos )
{
    HASH_BUCKET *Bucket;
    HASH_BUCKET *AllocBucket;

    Bucket = Pos ? ( *Pos ) : Table->InternalPointer;
    if ( Bucket )
    {
        if ( KeyType == HASH_KEY_IS_LONG )
        {
            KeyLength = 0;
            if ( !Bucket->KeyLength && Bucket->HashValue == Index )
                return TRUE;
            HashIndexDelete( Table, Index );
        }
        else if ( KeyType == HASH_KEY_IS_STRING )
        {
            if ( Bucket->KeyLength == KeyLength && memcmp( Bucket->Key, Key, KeyLength * sizeof( TCHAR ) ) == 0 )
                return TRUE;
            HashDelete( Table, Key, KeyLength );
        }
        else
        {
            return FALSE;
        }

        HANDLE_BLOCK_INTERRUPTIONS( );
        if ( Bucket->Next )
            Bucket->Next->Last = Bucket->Last;

        if ( Bucket->Last )
            Bucket->Last->Next = Bucket->Next;
        else
            Table->Buckets[Bucket->HashValue & Table->TableMask] = Bucket->Next;

        if ( Bucket->KeyLength != KeyLength )
        {
            AllocBucket = ( HASH_BUCKET* )HEAP_ALLOC( sizeof( HASH_BUCKET ) + ( KeyLength - 1 ) * sizeof( TCHAR ) );
            if ( AllocBucket == NULL )
                return FALSE;

            AllocBucket->KeyLength = KeyLength;
            if ( Bucket->Data == &Bucket->DataPtr )
                AllocBucket->Data = &AllocBucket->DataPtr;
            else
                AllocBucket->Data = Bucket->Data;

            AllocBucket->DataPtr = Bucket->DataPtr;
            AllocBucket->ListNext = Bucket->ListNext;
            AllocBucket->ListLast = Bucket->ListLast;
            if ( AllocBucket->ListNext )
                Bucket->ListNext->ListLast = AllocBucket;
            else
                Table->ListTail = AllocBucket;

            if ( AllocBucket->ListLast )
                Bucket->ListLast->ListNext = AllocBucket;
            else
                Table->ListHead = AllocBucket;

            if ( Table->InternalPointer == Bucket )
                Table->InternalPointer = AllocBucket;

            if ( Pos )
                *Pos = AllocBucket;

            HEAP_FREE( Bucket );
            Bucket = AllocBucket;
        }

        if ( KeyType == HASH_KEY_IS_LONG )
        {
            Bucket->HashValue = Index;
        }
        else
        {
            memcpy( Bucket->Key, Key, KeyLength * sizeof( TCHAR ) );
            Bucket->HashValue = Table->Hash( Key, KeyLength );
        }

        CONNECT_TO_BUCKET_LIST( Bucket, Table->Buckets[Bucket->HashValue & Table->TableMask] );
        Table->Buckets[Bucket->HashValue & Table->TableMask] = Bucket;
        HANDLE_UNBLOCK_INTERRUPTIONS( );
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

void HashCopy( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION CopyFunction, void *Buffer, ULONG Size )
{
    HASH_BUCKET *Bucket;
    void *Dest;

    UNREFERENCED_PARAMETER( Buffer );
    Bucket = Source->ListHead;
    while ( Bucket )
    {
        if ( Bucket->KeyLength )
            HashQuickUpdate( Target, Bucket->Key, Bucket->KeyLength, Bucket->HashValue, Bucket->Data, Size, &Dest );
        else
            HashIndexUpdate( Target, Bucket->HashValue, Bucket->Data, Size, &Dest );

        if ( CopyFunction )
            CopyFunction( Dest );
        Bucket = Bucket->ListNext;
    }
    Target->InternalPointer = Target->ListHead;
}

void HashMerge( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION CopyFunction, void *Buffer, ULONG Size, ULONG Overwrite )
{
    ULONG Flags;
    HASH_BUCKET *Bucket;
    void *Dest;

    UNREFERENCED_PARAMETER( Buffer );
    Flags = Overwrite ? HASH_UPDATE : HASH_ADD;
    Bucket = Source->ListHead;
    while ( Bucket )
    {
        if ( Bucket->KeyLength > 0 )
        {
            if ( HashQuickAddOrUpdate( Target, Bucket->Key, Bucket->KeyLength, Bucket->HashValue, Bucket->Data, Size, &Dest, Flags ) == TRUE && CopyFunction )
                CopyFunction( Dest );
        }
        else
        {
            if ( ( Flags == HASH_UPDATE || !HashIndexIsExist( Target, Bucket->HashValue ) ) && HashIndexUpdate( Target, Bucket->HashValue, Bucket->Data, Size, &Dest ) == TRUE && CopyFunction )
                CopyFunction( Dest );
        }
        Bucket = Bucket->ListNext;
    }
    Target->InternalPointer = Target->ListHead;
}

void HashMergeEx( HASH_TABLE *Target, HASH_TABLE *Source, HASH_COPY_FUNCTION CopyFunction, ULONG Size, MERGE_CHECKER_FUNCTION MergeCheckerFunction, void *Context )
{
    HASH_BUCKET *Bucket;
    void *Dest;

    Bucket = Source->ListHead;
    while ( Bucket )
    {
        if ( HashReplaceCheckerWrapper( Target, Bucket->Data, Bucket, Context, MergeCheckerFunction ) )
        {
            if ( HashQuickUpdate( Target, Bucket->Key, Bucket->KeyLength, Bucket->HashValue, Bucket->Data, Size, &Dest ) == TRUE && CopyFunction )
                CopyFunction( Dest );
        }
        Bucket = Bucket->ListNext;
    }
    Target->InternalPointer = Target->ListHead;
}

ULONG HashSort( HASH_TABLE *Table, HASH_SORT_FUNCTION SortFunction, HASH_COMPARE_FUNCTION CompareFunction, ULONG ReNumber )
{
    ULONG Iter;
    ULONG Iter1;
    HASH_BUCKET **Buckets;
    HASH_BUCKET *Bucket;

    if ( !( Table->NumOfElements > 1 ) && !( ReNumber && Table->NumOfElements > 0 ) )
        return TRUE;

    Buckets = ( HASH_BUCKET** )HEAP_ALLOC( Table->NumOfElements * sizeof( HASH_BUCKET * ) );
    if ( Buckets == NULL )
        return FALSE;

    Iter = 0;
    Bucket = Table->ListHead;
    while ( Bucket )
    {
        Buckets[Iter] = Bucket;
        Bucket = Bucket->ListNext;
        Iter++;
    }

    SortFunction( ( void* )Buckets, Iter, sizeof( HASH_BUCKET* ), CompareFunction );

    HANDLE_BLOCK_INTERRUPTIONS( );
    Table->ListHead = Buckets[0];
    Table->ListTail = NULL;
    Table->InternalPointer = Table->ListHead;

    Buckets[0]->ListLast = NULL;
    if ( Iter > 1 )
    {
        Buckets[0]->ListNext = Buckets[1];
        for ( Iter1 = 1; Iter1 < Iter - 1; Iter1++ )
        {
            Buckets[Iter1]->ListLast = Buckets[Iter1 - 1];
            Buckets[Iter1]->ListNext = Buckets[Iter1 + 1];
        }
        Buckets[Iter1]->ListLast = Buckets[Iter1 - 1];
        Buckets[Iter1]->ListNext = NULL;
    }
    else
    {
        Buckets[0]->ListNext = NULL;
    }
    Table->ListTail = Buckets[Iter - 1];

    HEAP_FREE( Buckets );
    HANDLE_UNBLOCK_INTERRUPTIONS( );

    if ( ReNumber )
    {
        Bucket = Table->ListHead;
        Iter = 0;
        while ( Bucket != NULL )
        {
            Bucket->KeyLength = 0;
            Bucket->HashValue = Iter++;
            Bucket = Bucket->ListNext;
        }
        Table->NextFreeElement = Iter;
        HashRefresh( Table );
    }

    return TRUE;
}

ULONG HashCompare( HASH_TABLE *Table1, HASH_TABLE *Table2, HASH_COMPARE_FUNCTION CompareFunction, ULONG Ordered )
{
    ULONG RetCode;
    HASH_BUCKET *Bucket1;
    HASH_BUCKET *Bucket2;
    void *Data2;

    HASH_PROTECT_RECURSION( Table1 );
    HASH_PROTECT_RECURSION( Table2 );

    RetCode = Table1->NumOfElements - Table2->NumOfElements;
    if ( RetCode )
    {
        HASH_UNPROTECT_RECURSION( Table1 );
        HASH_UNPROTECT_RECURSION( Table2 );
        return RetCode;
    }

    Bucket1 = Table1->ListHead;
    Bucket2 = NULL;
    if ( Ordered )
        Bucket2 = Table2->ListHead;

    while ( Bucket1 )
    {
        if ( Ordered && !Bucket2 )
        {
            /* That's not supposed to happen */
            HASH_UNPROTECT_RECURSION( Table1 );
            HASH_UNPROTECT_RECURSION( Table2 );
            return 1;
        }
        if ( Ordered )
        {
            if ( Bucket1->KeyLength == 0 && Bucket2->KeyLength == 0 )
            {
                /* Numeric */
                RetCode = Bucket1->HashValue - Bucket2->HashValue;
                if ( RetCode )
                {
                    HASH_UNPROTECT_RECURSION( Table1 );
                    HASH_UNPROTECT_RECURSION( Table2 );
                    return RetCode;
                }
            }
            else
            {
                /* String */
                RetCode = Bucket1->KeyLength - Bucket2->KeyLength;
                if ( RetCode )
                {
                    HASH_UNPROTECT_RECURSION( Table1 );
                    HASH_UNPROTECT_RECURSION( Table2 );
                    return RetCode;
                }

                RetCode = memcmp( Bucket1->Key, Bucket2->Key, Bucket1->KeyLength );
                if ( RetCode )
                {
                    HASH_UNPROTECT_RECURSION( Table1 );
                    HASH_UNPROTECT_RECURSION( Table2 );
                    return RetCode;
                }
            }
            Data2 = Bucket2->Data;
        }
        else
        {
            if ( Bucket1->KeyLength == 0 )
            {
                /* Numeric index */
                if ( HashIndexFind( Table2, Bucket1->HashValue, &Data2 ) == FALSE )
                {
                    HASH_UNPROTECT_RECURSION( Table1 );
                    HASH_UNPROTECT_RECURSION( Table2 );
                    return 1;
                }
            }
            else
            {
                /* String index */
                if ( HashFind( Table2, Bucket1->Key, Bucket1->KeyLength, &Data2 ) == FALSE )
                {
                    HASH_UNPROTECT_RECURSION( Table1 );
                    HASH_UNPROTECT_RECURSION( Table2 );
                    return 1;
                }
            }
        }
        RetCode = CompareFunction( Bucket1->Data, Data2 );
        if ( RetCode )
        {
            HASH_UNPROTECT_RECURSION( Table1 );
            HASH_UNPROTECT_RECURSION( Table2 );
            return RetCode;
        }

        Bucket1 = Bucket1->ListNext;
        if ( Ordered )
            Bucket2 = Bucket2->ListNext;
    }

    HASH_UNPROTECT_RECURSION( Table1 );
    HASH_UNPROTECT_RECURSION( Table2 );

    return 0;
}

ULONG HashMinMax( HASH_TABLE *Table, HASH_COMPARE_FUNCTION CompareFunction, ULONG Flags, void **Data )
{
    HASH_BUCKET *RetCode;
    HASH_BUCKET *Bucket;

    if ( Table->NumOfElements == 0 )
    {
        *Data = NULL;
        return FALSE;
    }

    RetCode = Bucket = Table->ListHead;
    while ( ( Bucket = Bucket->ListNext ) )
    {
        if ( Flags )
        {
            if ( CompareFunction( &RetCode, &Bucket ) < 0 )
            {
                /* Max */
                RetCode = Bucket;
            }
        }
        else
        {
            if ( CompareFunction( &RetCode, &Bucket ) > 0 )
            {
                /* Min */
                RetCode = Bucket;
            }
        }
    }
    *Data = RetCode->Data;

    return TRUE;
}

ULONG HashGetValue( const TCHAR *Key, ULONG KeyLength )
{
    return DefaultHashFunctionInline( Key, KeyLength );
}

ULONG HashGetCount( const HASH_TABLE *Table )
{
    return Table->NumOfElements;
}

ULONG HashGetNextFreeElement( const HASH_TABLE *Table )
{
    return Table->NextFreeElement;
}

ULONG HashRefresh( HASH_TABLE *Table )
{
    ULONG Index;
    HASH_BUCKET *Bucket;

    memset( Table->Buckets, 0, Table->TableSize * sizeof( HASH_BUCKET * ) );
    Bucket = Table->ListHead;
    while ( Bucket != NULL )
    {
        Index = Bucket->HashValue & Table->TableMask;
        CONNECT_TO_BUCKET_LIST( Bucket, Table->Buckets[Index] );
        Table->Buckets[Index] = Bucket;
        Bucket = Bucket->ListNext;
    }

    return TRUE;
}

请问php源码部分是基于哪个 svn revision 的?

请问php源码部分是基于哪个 svn revision 的?

按您所说,07年的时候 php 是用 svn 做源码管理的(现在转到git了)。
那么请问当时开发dezend的时候是基于哪个 svn revision 的呢。

需要剥离出dezend对php的修改部分才能继续拜读这份代码。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.