Merge.
Merge.
1.1 --- a/configs/core.cfg Fri Aug 10 21:49:40 2012 -0400
1.2 +++ b/configs/core.cfg Fri Aug 10 21:54:03 2012 -0400
1.3 @@ -115,4 +115,14 @@
1.4 * In general, this option should be set to "yes" to increase the security of your server.
1.5 */
1.6 "SteamAuthstringValidation" "yes"
1.7 +
1.8 + /**
1.9 + * Enables or disables whether SourceMod blocks known or potentially malicious plugins from loading.
1.10 + * It is STRONGLY advised that this is left enabled, there have been cases in the past with plugins that
1.11 + * allow anyone to delete files on the server, gain full rcon control, etc.
1.12 + *
1.13 + * "yes" - Block malware or illegal plugins from loading (default)
1.14 + * "no" - Warn about malware or illegal plugins loading
1.15 + */
1.16 + "BlockBadPlugins" "yes"
1.17 }
2.1 --- a/core/PluginSys.cpp Fri Aug 10 21:49:40 2012 -0400
2.2 +++ b/core/PluginSys.cpp Fri Aug 10 21:54:03 2012 -0400
2.3 @@ -789,6 +789,8 @@
2.4 m_AllPluginsLoaded = false;
2.5 m_MyIdent = NULL;
2.6 m_LoadingLocked = false;
2.7 +
2.8 + m_bBlockBadPlugins = true;
2.9 }
2.10
2.11 CPluginManager::~CPluginManager()
2.12 @@ -1030,6 +1032,41 @@
2.13 }
2.14 }
2.15 }
2.16 +
2.17 + if (pPlugin->GetStatus() == Plugin_Created)
2.18 + {
2.19 + unsigned char *pCodeHash = pPlugin->m_pRuntime->GetCodeHash();
2.20 +
2.21 + char codeHashBuf[40];
2.22 + UTIL_Format(codeHashBuf, 40, "plugin_");
2.23 + for (int i = 0; i < 16; i++)
2.24 + UTIL_Format(codeHashBuf + 7 + (i * 2), 3, "%02x", pCodeHash[i]);
2.25 +
2.26 + const char *bulletinUrl = g_pGameConf->GetKeyValue(codeHashBuf);
2.27 + if (bulletinUrl != NULL)
2.28 + {
2.29 + if (m_bBlockBadPlugins)
2.30 + {
2.31 + if (error)
2.32 + {
2.33 + if (bulletinUrl[0] != '\0')
2.34 + {
2.35 + UTIL_Format(error, maxlength, "Known malware detected and blocked. See %s for more info", bulletinUrl);
2.36 + } else {
2.37 + UTIL_Format(error, maxlength, "Possible malware or illegal plugin detected and blocked");
2.38 + }
2.39 + }
2.40 + pPlugin->m_status = Plugin_BadLoad;
2.41 + } else {
2.42 + if (bulletinUrl[0] != '\0')
2.43 + {
2.44 + g_Logger.LogMessage("%s: Known malware detected. See %s for more info, blocking disabled in core.cfg", pPlugin->GetFilename(), bulletinUrl);
2.45 + } else {
2.46 + g_Logger.LogMessage("%s: Possible malware or illegal plugin detected, blocking disabled in core.cfg", pPlugin->GetFilename());
2.47 + }
2.48 + }
2.49 + }
2.50 + }
2.51
2.52 LoadRes loadFailure = LoadRes_Failure;
2.53 /* Get the status */
2.54 @@ -1129,7 +1166,7 @@
2.55
2.56 if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
2.57 {
2.58 - g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
2.59 + g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s.", plugin, error);
2.60 pl->SetErrorState(
2.61 pl->GetStatus() <= Plugin_Created ? Plugin_BadLoad : pl->GetStatus(),
2.62 "%s",
2.63 @@ -1889,6 +1926,27 @@
2.64 g_ShareSys.DestroyIdentity(m_MyIdent);
2.65 }
2.66
2.67 +ConfigResult CPluginManager::OnSourceModConfigChanged(const char *key,
2.68 + const char *value,
2.69 + ConfigSource source,
2.70 + char *error,
2.71 + size_t maxlength)
2.72 +{
2.73 + if (strcmp(key, "BlockBadPlugins") == 0) {
2.74 + if (strcasecmp(value, "yes") == 0)
2.75 + {
2.76 + m_bBlockBadPlugins = true;
2.77 + } else if (strcasecmp(value, "no") == 0) {
2.78 + m_bBlockBadPlugins = false;
2.79 + } else {
2.80 + UTIL_Format(error, maxlength, "Invalid value: must be \"yes\" or \"no\"");
2.81 + return ConfigResult_Reject;
2.82 + }
2.83 + return ConfigResult_Accept;
2.84 + }
2.85 + return ConfigResult_Ignore;
2.86 +}
2.87 +
2.88 void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
2.89 {
2.90 /* We don't care about the internal object, actually */
2.91 @@ -2269,6 +2327,15 @@
2.92 {
2.93 g_RootMenu.ConsolePrint(" Timestamp: %s", pl->m_DateTime);
2.94 }
2.95 +
2.96 + unsigned char *pCodeHash = pl->m_pRuntime->GetCodeHash();
2.97 + unsigned char *pDataHash = pl->m_pRuntime->GetDataHash();
2.98 +
2.99 + char combinedHash[33];
2.100 + for (int i = 0; i < 16; i++)
2.101 + UTIL_Format(combinedHash + (i * 2), 3, "%02x", pCodeHash[i] ^ pDataHash[i]);
2.102 +
2.103 + g_RootMenu.ConsolePrint(" Hash: %s", combinedHash);
2.104 }
2.105 else
2.106 {
3.1 --- a/core/PluginSys.h Fri Aug 10 21:49:40 2012 -0400
3.2 +++ b/core/PluginSys.h Fri Aug 10 21:54:03 2012 -0400
3.3 @@ -57,6 +57,7 @@
3.4 #include "convar_sm.h"
3.5 #endif
3.6 #include "ITranslator.h"
3.7 +#include "IGameConfigs.h"
3.8 #include "NativeOwner.h"
3.9 #include "ShareSys.h"
3.10
3.11 @@ -326,6 +327,7 @@
3.12 public: //SMGlobalClass
3.13 void OnSourceModAllInitialized();
3.14 void OnSourceModShutdown();
3.15 + ConfigResult OnSourceModConfigChanged(const char *key, const char *value, ConfigSource source, char *error, size_t maxlength);
3.16 void OnSourceModMaxPlayersChanged(int newvalue);
3.17 public: //IHandleTypeDispatch
3.18 void OnHandleDestroy(HandleType_t type, void *object);
3.19 @@ -470,6 +472,9 @@
3.20 List<FakeNative *> m_Natives;
3.21
3.22 bool m_LoadingLocked;
3.23 +
3.24 + // Config
3.25 + bool m_bBlockBadPlugins;
3.26 };
3.27
3.28 extern CPluginManager g_PluginSys;
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/gamedata/core.games/blacklist.plugins.txt Fri Aug 10 21:54:03 2012 -0400
4.3 @@ -0,0 +1,16 @@
4.4 +/**
4.5 + * Do not edit this file. Any changes will be overwritten by the gamedata
4.6 + * updater or by upgrading your SourceMod install.
4.7 + *
4.8 + * For more information, see http://wiki.alliedmods.net/Gamedata_Updating_(SourceMod)
4.9 + */
4.10 +
4.11 +"Games"
4.12 +{
4.13 + "#default"
4.14 + {
4.15 + "Keys"
4.16 + {
4.17 + }
4.18 + }
4.19 +}
5.1 --- a/gamedata/core.games/master.games.txt Fri Aug 10 21:49:40 2012 -0400
5.2 +++ b/gamedata/core.games/master.games.txt Fri Aug 10 21:54:03 2012 -0400
5.3 @@ -65,4 +65,7 @@
5.4 "engine" "csgo"
5.5 }
5.6
5.7 + "blacklist.plugins.txt"
5.8 + {
5.9 + }
5.10 }
6.1 --- a/plugins/include/tf2_stocks.inc Fri Aug 10 21:49:40 2012 -0400
6.2 +++ b/plugins/include/tf2_stocks.inc Fri Aug 10 21:54:03 2012 -0400
6.3 @@ -231,7 +231,7 @@
6.4 TF_WEAPON_GRENADE_CLEAVER,
6.5 };
6.6
6.7 -// TF2 Weapon Slots for GetPlayerWeaponSlot
6.8 +// TF2 Weapon Loadout Slots
6.9 enum
6.10 {
6.11 TFWeaponSlot_Primary,
7.1 --- a/public/sourcepawn/sp_vm_api.h Fri Aug 10 21:49:40 2012 -0400
7.2 +++ b/public/sourcepawn/sp_vm_api.h Fri Aug 10 21:54:03 2012 -0400
7.3 @@ -40,7 +40,7 @@
7.4
7.5 /** SourcePawn Engine API Version */
7.6 #define SOURCEPAWN_ENGINE_API_VERSION 4
7.7 -#define SOURCEPAWN_ENGINE2_API_VERSION 3
7.8 +#define SOURCEPAWN_ENGINE2_API_VERSION 4
7.9
7.10 #if !defined SOURCEMOD_BUILD
7.11 #define SOURCEMOD_BUILD
7.12 @@ -479,6 +479,20 @@
7.13 * @return Memory usage, in bytes.
7.14 */
7.15 virtual size_t GetMemUsage() =0;
7.16 +
7.17 + /**
7.18 + * @brief Returns the MD5 hash of the plugin's P-Code.
7.19 + *
7.20 + * @return 16-byte buffer with MD5 hash of the plugin's P-Code.
7.21 + */
7.22 + virtual unsigned char *GetCodeHash() =0;
7.23 +
7.24 + /**
7.25 + * @brief Returns the MD5 hash of the plugin's Data.
7.26 + *
7.27 + * @return 16-byte buffer with MD5 hash of the plugin's Data.
7.28 + */
7.29 + virtual unsigned char *GetDataHash() =0;
7.30 };
7.31
7.32 /**
8.1 --- a/sourcepawn/jit/AMBuilder Fri Aug 10 21:49:40 2012 -0400
8.2 +++ b/sourcepawn/jit/AMBuilder Fri Aug 10 21:54:03 2012 -0400
8.3 @@ -36,6 +36,7 @@
8.4 'zlib/trees.c',
8.5 'zlib/uncompr.c',
8.6 'zlib/zutil.c',
8.7 + 'md5/md5.cpp',
8.8 '../../knight/shared/KeCodeAllocator.cpp'
8.9 ])
8.10 SM.AutoVersion('sourcepawn/jit', binary)
9.1 --- a/sourcepawn/jit/BaseRuntime.cpp Fri Aug 10 21:49:40 2012 -0400
9.2 +++ b/sourcepawn/jit/BaseRuntime.cpp Fri Aug 10 21:54:03 2012 -0400
9.3 @@ -8,6 +8,8 @@
9.4 #include "sp_vm_basecontext.h"
9.5 #include "engine2.h"
9.6
9.7 +#include "md5/md5.h"
9.8 +
9.9 using namespace SourcePawn;
9.10
9.11 BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL),
9.12 @@ -18,6 +20,9 @@
9.13 m_FuncCache = NULL;
9.14 m_MaxFuncs = 0;
9.15 m_NumFuncs = 0;
9.16 +
9.17 + memset(m_CodeHash, 0, sizeof(m_CodeHash));
9.18 + memset(m_DataHash, 0, sizeof(m_DataHash));
9.19 }
9.20
9.21 BaseRuntime::~BaseRuntime()
9.22 @@ -227,6 +232,16 @@
9.23 memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
9.24 }
9.25
9.26 + MD5 md5_pcode;
9.27 + md5_pcode.update(plugin->pcode, plugin->pcode_size);
9.28 + md5_pcode.finalize();
9.29 + md5_pcode.raw_digest(m_CodeHash);
9.30 +
9.31 + MD5 md5_data;
9.32 + md5_data.update(plugin->data, plugin->data_size);
9.33 + md5_data.finalize();
9.34 + md5_data.raw_digest(m_DataHash);
9.35 +
9.36 m_pPlugin->profiler = g_engine2.GetProfiler();
9.37 m_pCtx = new BaseContext(this);
9.38 m_pCo = g_Jit.StartCompilation(this);
9.39 @@ -483,6 +498,16 @@
9.40 return mem;
9.41 }
9.42
9.43 +unsigned char *BaseRuntime::GetCodeHash()
9.44 +{
9.45 + return m_CodeHash;
9.46 +}
9.47 +
9.48 +unsigned char *BaseRuntime::GetDataHash()
9.49 +{
9.50 + return m_DataHash;
9.51 +}
9.52 +
9.53 BaseContext *BaseRuntime::GetBaseContext()
9.54 {
9.55 return m_pCtx;
10.1 --- a/sourcepawn/jit/BaseRuntime.h Fri Aug 10 21:49:40 2012 -0400
10.2 +++ b/sourcepawn/jit/BaseRuntime.h Fri Aug 10 21:54:03 2012 -0400
10.3 @@ -48,6 +48,8 @@
10.4 virtual void SetPauseState(bool paused);
10.5 virtual bool IsPaused();
10.6 virtual size_t GetMemUsage();
10.7 + virtual unsigned char *GetCodeHash();
10.8 + virtual unsigned char *GetDataHash();
10.9 JitFunction *GetJittedFunction(uint32_t idx);
10.10 uint32_t AddJittedFunction(JitFunction *fn);
10.11 public:
10.12 @@ -65,6 +67,9 @@
10.13 JitFunction **m_PubJitFuncs;
10.14 ICompilation *m_pCo;
10.15 unsigned int m_CompSerial;
10.16 +
10.17 + unsigned char m_CodeHash[16];
10.18 + unsigned char m_DataHash[16];
10.19 };
10.20
10.21 #endif //_INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/sourcepawn/jit/md5/md5.cpp Fri Aug 10 21:54:03 2012 -0400
11.3 @@ -0,0 +1,476 @@
11.4 +// MD5.CC - source code for the C++/object oriented translation and
11.5 +// modification of MD5.
11.6 +
11.7 +// Translation and modification (c) 1995 by Mordechai T. Abzug
11.8 +
11.9 +// This translation/ modification is provided "as is," without express or
11.10 +// implied warranty of any kind.
11.11 +
11.12 +// The translator/ modifier does not claim (1) that MD5 will do what you think
11.13 +// it does; (2) that this translation/ modification is accurate; or (3) that
11.14 +// this software is "merchantible." (Language for this disclaimer partially
11.15 +// copied from the disclaimer below).
11.16 +
11.17 +/* based on:
11.18 +
11.19 + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
11.20 + MDDRIVER.C - test driver for MD2, MD4 and MD5
11.21 +
11.22 +
11.23 + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
11.24 +rights reserved.
11.25 +
11.26 +License to copy and use this software is granted provided that it
11.27 +is identified as the "RSA Data Security, Inc. MD5 Message-Digest
11.28 +Algorithm" in all material mentioning or referencing this software
11.29 +or this function.
11.30 +
11.31 +License is also granted to make and use derivative works provided
11.32 +that such works are identified as "derived from the RSA Data
11.33 +Security, Inc. MD5 Message-Digest Algorithm" in all material
11.34 +mentioning or referencing the derived work.
11.35 +
11.36 +RSA Data Security, Inc. makes no representations concerning either
11.37 +the merchantability of this software or the suitability of this
11.38 +software for any particular purpose. It is provided "as is"
11.39 +without express or implied warranty of any kind.
11.40 +
11.41 +These notices must be retained in any copies of any part of this
11.42 +documentation and/or software.
11.43 +
11.44 + */
11.45 +
11.46 +#include "md5.h"
11.47 +
11.48 +#include <assert.h>
11.49 +#include <string.h>
11.50 +
11.51 +// MD5 simple initialization method
11.52 +
11.53 +MD5::MD5(){
11.54 +
11.55 + init();
11.56 +
11.57 +}
11.58 +
11.59 +
11.60 +// MD5 block update operation. Continues an MD5 message-digest
11.61 +// operation, processing another message block, and updating the
11.62 +// context.
11.63 +
11.64 +void MD5::update (uint1 *input, uint4 input_length) {
11.65 +
11.66 + uint4 input_index, buffer_index;
11.67 + uint4 buffer_space; // how much space is left in buffer
11.68 +
11.69 + if (finalized){ // so we can't update!
11.70 + /*cerr << "MD5::update: Can't update a finalized digest!" << endl;*/
11.71 + return;
11.72 + }
11.73 +
11.74 + // Compute number of bytes mod 64
11.75 + buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
11.76 +
11.77 + // Update number of bits
11.78 + if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
11.79 + count[1]++;
11.80 +
11.81 + count[1] += ((uint4)input_length >> 29);
11.82 +
11.83 +
11.84 + buffer_space = 64 - buffer_index; // how much space is left in buffer
11.85 +
11.86 + // Transform as many times as possible.
11.87 + if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
11.88 + // fill the rest of the buffer and transform
11.89 + memcpy (buffer + buffer_index, input, buffer_space);
11.90 + transform (buffer);
11.91 +
11.92 + // now, transform each 64-byte piece of the input, bypassing the buffer
11.93 + for (input_index = buffer_space; input_index + 63 < input_length;
11.94 + input_index += 64)
11.95 + transform (input+input_index);
11.96 +
11.97 + buffer_index = 0; // so we can buffer remaining
11.98 + }
11.99 + else
11.100 + input_index=0; // so we can buffer the whole input
11.101 +
11.102 +
11.103 + // and here we do the buffering:
11.104 + memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
11.105 +}
11.106 +
11.107 +
11.108 +
11.109 +// MD5 update for files.
11.110 +// Like above, except that it works on files (and uses above as a primitive.)
11.111 +
11.112 +void MD5::update(FILE *file){
11.113 +
11.114 + unsigned char buffer[1024];
11.115 + int len;
11.116 +
11.117 + while ((len=fread(buffer, 1, 1024, file)))
11.118 + update(buffer, len);
11.119 +
11.120 + fclose (file);
11.121 +
11.122 +}
11.123 +
11.124 +
11.125 +// MD5 finalization. Ends an MD5 message-digest operation, writing the
11.126 +// the message digest and zeroizing the context.
11.127 +
11.128 +
11.129 +void MD5::finalize (){
11.130 +
11.131 + unsigned char bits[8];
11.132 + unsigned int index, padLen;
11.133 + static uint1 PADDING[64]={
11.134 + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11.135 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
11.136 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
11.137 + };
11.138 +
11.139 + if (finalized){
11.140 + /* cerr << "MD5::finalize: Already finalized this digest!" << endl;*/
11.141 + return;
11.142 + }
11.143 +
11.144 + // Save number of bits
11.145 + encode (bits, count, 8);
11.146 +
11.147 + // Pad out to 56 mod 64.
11.148 + index = (uint4) ((count[0] >> 3) & 0x3f);
11.149 + padLen = (index < 56) ? (56 - index) : (120 - index);
11.150 + update (PADDING, padLen);
11.151 +
11.152 + // Append length (before padding)
11.153 + update (bits, 8);
11.154 +
11.155 + // Store state in digest
11.156 + encode (digest, state, 16);
11.157 +
11.158 + // Zeroize sensitive information
11.159 + memset (buffer, 0, sizeof(*buffer));
11.160 +
11.161 + finalized=1;
11.162 +
11.163 +}
11.164 +
11.165 +
11.166 +
11.167 +
11.168 +MD5::MD5(FILE *file){
11.169 +
11.170 + init(); // must be called be all constructors
11.171 + update(file);
11.172 + finalize ();
11.173 +}
11.174 +
11.175 +unsigned char *MD5::raw_digest(){
11.176 +
11.177 + uint1 *s = new uint1[16];
11.178 +
11.179 + if (!finalized){
11.180 +/* cerr << "MD5::raw_digest: Can't get digest if you haven't "<<
11.181 + "finalized the digest!" <<endl;*/
11.182 + return ( (unsigned char*) "");
11.183 + }
11.184 +
11.185 + memcpy(s, digest, 16);
11.186 + return s;
11.187 +}
11.188 +
11.189 +unsigned char *MD5::raw_digest(unsigned char buffer[16])
11.190 +{
11.191 + if (!finalized)
11.192 + {
11.193 + return ( (unsigned char*) "");
11.194 + }
11.195 +
11.196 + memcpy(buffer, digest, 16);
11.197 + return buffer;
11.198 +}
11.199 +
11.200 +
11.201 +
11.202 +char *MD5::hex_digest(){
11.203 +
11.204 + int i;
11.205 + char *s= new char[33];
11.206 +
11.207 + assert(finalized);
11.208 +
11.209 + for (i=0; i<16; i++)
11.210 + sprintf(s+i*2, "%02x", digest[i]);
11.211 +
11.212 + s[32]='\0';
11.213 +
11.214 + return s;
11.215 +}
11.216 +
11.217 +
11.218 +char *MD5::hex_digest(char buffer[33]){
11.219 +
11.220 + int i;
11.221 +
11.222 + assert(finalized);
11.223 +
11.224 + for (i=0; i<16; i++)
11.225 + sprintf(buffer+i*2, "%02x", digest[i]);
11.226 +
11.227 + buffer[32]='\0';
11.228 +
11.229 + return buffer;
11.230 +}
11.231 +
11.232 +
11.233 +// PRIVATE METHODS:
11.234 +
11.235 +
11.236 +
11.237 +void MD5::init(){
11.238 + finalized=0; // we just started!
11.239 +
11.240 + // Nothing counted, so count=0
11.241 + count[0] = 0;
11.242 + count[1] = 0;
11.243 +
11.244 + // Load magic initialization constants.
11.245 + state[0] = 0x67452301;
11.246 + state[1] = 0xefcdab89;
11.247 + state[2] = 0x98badcfe;
11.248 + state[3] = 0x10325476;
11.249 +}
11.250 +
11.251 +
11.252 +
11.253 +// Constants for MD5Transform routine.
11.254 +// Although we could use C++ style constants, defines are actually better,
11.255 +// since they let us easily evade scope clashes.
11.256 +
11.257 +#define S11 7
11.258 +#define S12 12
11.259 +#define S13 17
11.260 +#define S14 22
11.261 +#define S21 5
11.262 +#define S22 9
11.263 +#define S23 14
11.264 +#define S24 20
11.265 +#define S31 4
11.266 +#define S32 11
11.267 +#define S33 16
11.268 +#define S34 23
11.269 +#define S41 6
11.270 +#define S42 10
11.271 +#define S43 15
11.272 +#define S44 21
11.273 +
11.274 +
11.275 +
11.276 +
11.277 +// MD5 basic transformation. Transforms state based on block.
11.278 +void MD5::transform (uint1 block[64]){
11.279 +
11.280 + uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
11.281 +
11.282 + decode (x, block, 64);
11.283 +
11.284 + assert(!finalized); // not just a user error, since the method is private
11.285 +
11.286 + /* Round 1 */
11.287 + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
11.288 + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
11.289 + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
11.290 + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
11.291 + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
11.292 + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
11.293 + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
11.294 + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
11.295 + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
11.296 + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
11.297 + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
11.298 + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
11.299 + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
11.300 + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
11.301 + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
11.302 + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
11.303 +
11.304 + /* Round 2 */
11.305 + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
11.306 + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
11.307 + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
11.308 + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
11.309 + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
11.310 + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
11.311 + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
11.312 + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
11.313 + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
11.314 + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
11.315 + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
11.316 + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
11.317 + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
11.318 + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
11.319 + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
11.320 + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
11.321 +
11.322 + /* Round 3 */
11.323 + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
11.324 + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
11.325 + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
11.326 + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
11.327 + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
11.328 + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
11.329 + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
11.330 + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
11.331 + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
11.332 + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
11.333 + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
11.334 + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
11.335 + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
11.336 + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
11.337 + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
11.338 + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
11.339 +
11.340 + /* Round 4 */
11.341 + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
11.342 + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
11.343 + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
11.344 + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
11.345 + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
11.346 + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
11.347 + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
11.348 + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
11.349 + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
11.350 + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
11.351 + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
11.352 + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
11.353 + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
11.354 + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
11.355 + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
11.356 + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
11.357 +
11.358 + state[0] += a;
11.359 + state[1] += b;
11.360 + state[2] += c;
11.361 + state[3] += d;
11.362 +
11.363 + // Zeroize sensitive information.
11.364 + memset ( (uint1 *) x, 0, sizeof(x));
11.365 +
11.366 +}
11.367 +
11.368 +
11.369 +
11.370 +// Encodes input (UINT4) into output (unsigned char). Assumes len is
11.371 +// a multiple of 4.
11.372 +void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
11.373 +
11.374 + unsigned int i, j;
11.375 +
11.376 + for (i = 0, j = 0; j < len; i++, j += 4) {
11.377 + output[j] = (uint1) (input[i] & 0xff);
11.378 + output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
11.379 + output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
11.380 + output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
11.381 + }
11.382 +}
11.383 +
11.384 +
11.385 +
11.386 +
11.387 +// Decodes input (unsigned char) into output (UINT4). Assumes len is
11.388 +// a multiple of 4.
11.389 +void MD5::decode (uint4 *output, uint1 *input, uint4 len){
11.390 +
11.391 + unsigned int i, j;
11.392 +
11.393 + for (i = 0, j = 0; j < len; i++, j += 4)
11.394 + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
11.395 + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
11.396 +}
11.397 +
11.398 +
11.399 +
11.400 +
11.401 +
11.402 +// Note: Replace "for loop" with standard memcpy if possible.
11.403 +void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
11.404 +
11.405 + unsigned int i;
11.406 +
11.407 + for (i = 0; i < len; i++)
11.408 + output[i] = input[i];
11.409 +}
11.410 +
11.411 +
11.412 +
11.413 +// Note: Replace "for loop" with standard memset if possible.
11.414 +void MD5::memset (uint1 *output, uint1 value, uint4 len){
11.415 +
11.416 + unsigned int i;
11.417 +
11.418 + for (i = 0; i < len; i++)
11.419 + output[i] = value;
11.420 +}
11.421 +
11.422 +
11.423 +
11.424 +// ROTATE_LEFT rotates x left n bits.
11.425 +
11.426 +inline unsigned int MD5::rotate_left (uint4 x, uint4 n){
11.427 + return (x << n) | (x >> (32-n)) ;
11.428 +}
11.429 +
11.430 +
11.431 +
11.432 +
11.433 +// F, G, H and I are basic MD5 functions.
11.434 +
11.435 +inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){
11.436 + return (x & y) | (~x & z);
11.437 +}
11.438 +
11.439 +inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){
11.440 + return (x & z) | (y & ~z);
11.441 +}
11.442 +
11.443 +inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){
11.444 + return x ^ y ^ z;
11.445 +}
11.446 +
11.447 +inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){
11.448 + return y ^ (x | ~z);
11.449 +}
11.450 +
11.451 +
11.452 +
11.453 +// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
11.454 +// Rotation is separate from addition to prevent recomputation.
11.455 +
11.456 +
11.457 +inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
11.458 + uint4 s, uint4 ac){
11.459 + a += F(b, c, d) + x + ac;
11.460 + a = rotate_left (a, s) +b;
11.461 +}
11.462 +
11.463 +inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
11.464 + uint4 s, uint4 ac){
11.465 + a += G(b, c, d) + x + ac;
11.466 + a = rotate_left (a, s) +b;
11.467 +}
11.468 +
11.469 +inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
11.470 + uint4 s, uint4 ac){
11.471 + a += H(b, c, d) + x + ac;
11.472 + a = rotate_left (a, s) +b;
11.473 +}
11.474 +
11.475 +inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
11.476 + uint4 s, uint4 ac){
11.477 + a += I(b, c, d) + x + ac;
11.478 + a = rotate_left (a, s) +b;
11.479 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/sourcepawn/jit/md5/md5.h Fri Aug 10 21:54:03 2012 -0400
12.3 @@ -0,0 +1,106 @@
12.4 +// MD5.CC - source code for the C++/object oriented translation and
12.5 +// modification of MD5.
12.6 +
12.7 +// Translation and modification (c) 1995 by Mordechai T. Abzug
12.8 +
12.9 +// This translation/ modification is provided "as is," without express or
12.10 +// implied warranty of any kind.
12.11 +
12.12 +// The translator/ modifier does not claim (1) that MD5 will do what you think
12.13 +// it does; (2) that this translation/ modification is accurate; or (3) that
12.14 +// this software is "merchantible." (Language for this disclaimer partially
12.15 +// copied from the disclaimer below).
12.16 +
12.17 +/* based on:
12.18 +
12.19 + MD5.H - header file for MD5C.C
12.20 + MDDRIVER.C - test driver for MD2, MD4 and MD5
12.21 +
12.22 + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
12.23 +rights reserved.
12.24 +
12.25 +License to copy and use this software is granted provided that it
12.26 +is identified as the "RSA Data Security, Inc. MD5 Message-Digest
12.27 +Algorithm" in all material mentioning or referencing this software
12.28 +or this function.
12.29 +
12.30 +License is also granted to make and use derivative works provided
12.31 +that such works are identified as "derived from the RSA Data
12.32 +Security, Inc. MD5 Message-Digest Algorithm" in all material
12.33 +mentioning or referencing the derived work.
12.34 +
12.35 +RSA Data Security, Inc. makes no representations concerning either
12.36 +the merchantability of this software or the suitability of this
12.37 +software for any particular purpose. It is provided "as is"
12.38 +without express or implied warranty of any kind.
12.39 +
12.40 +These notices must be retained in any copies of any part of this
12.41 +documentation and/or software.
12.42 +
12.43 +*/
12.44 +
12.45 +#include <stdio.h>
12.46 +//#include <fstream.h>
12.47 +//#include <iostream.h>
12.48 +
12.49 +class MD5 {
12.50 +
12.51 +public:
12.52 +// methods for controlled operation:
12.53 + MD5 (); // simple initializer
12.54 + void update (unsigned char *input, unsigned int input_length);
12.55 + void update (FILE *file);
12.56 + void finalize ();
12.57 +
12.58 +// constructors for special circumstances. All these constructors finalize
12.59 +// the MD5 context.
12.60 + MD5 (unsigned char *string); // digest string, finalize
12.61 + MD5 (FILE *file); // digest file, close, finalize
12.62 +
12.63 +// methods to acquire finalized result
12.64 + unsigned char *raw_digest (); // digest as a 16-byte binary array
12.65 + unsigned char *raw_digest(unsigned char buffer[16]);
12.66 + char * hex_digest (); // digest as a 33-byte ascii-hex string
12.67 + char * hex_digest (char buffer[33]); //same as above, passing buffer
12.68 +
12.69 +
12.70 +
12.71 +private:
12.72 +
12.73 +// first, some types:
12.74 + typedef unsigned int uint4; // assumes integer is 4 words long
12.75 + typedef unsigned short int uint2; // assumes short integer is 2 words long
12.76 + typedef unsigned char uint1; // assumes char is 1 word long
12.77 +
12.78 +// next, the private data:
12.79 + uint4 state[4];
12.80 + uint4 count[2]; // number of *bits*, mod 2^64
12.81 + uint1 buffer[64]; // input buffer
12.82 + uint1 digest[16];
12.83 + uint1 finalized;
12.84 +
12.85 +// last, the private methods, mostly static:
12.86 + void init (); // called by all constructors
12.87 + void transform (uint1 *buffer); // does the real update work. Note
12.88 + // that length is implied to be 64.
12.89 +
12.90 + static void encode (uint1 *dest, uint4 *src, uint4 length);
12.91 + static void decode (uint4 *dest, uint1 *src, uint4 length);
12.92 + static void memcpy (uint1 *dest, uint1 *src, uint4 length);
12.93 + static void memset (uint1 *start, uint1 val, uint4 length);
12.94 +
12.95 + static inline uint4 rotate_left (uint4 x, uint4 n);
12.96 + static inline uint4 F (uint4 x, uint4 y, uint4 z);
12.97 + static inline uint4 G (uint4 x, uint4 y, uint4 z);
12.98 + static inline uint4 H (uint4 x, uint4 y, uint4 z);
12.99 + static inline uint4 I (uint4 x, uint4 y, uint4 z);
12.100 + static inline void FF (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
12.101 + uint4 s, uint4 ac);
12.102 + static inline void GG (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
12.103 + uint4 s, uint4 ac);
12.104 + static inline void HH (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
12.105 + uint4 s, uint4 ac);
12.106 + static inline void II (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x,
12.107 + uint4 s, uint4 ac);
12.108 +
12.109 +};
13.1 --- a/tools/ida_scripts/vtable_dump.py Fri Aug 10 21:49:40 2012 -0400
13.2 +++ b/tools/ida_scripts/vtable_dump.py Fri Aug 10 21:54:03 2012 -0400
13.3 @@ -18,6 +18,79 @@
13.4
13.5 import re
13.6
13.7 +"""
13.8 +Output Format:"
13.9 + VTable for <1>: (<2>, <3>)
13.10 + Lin Win Function
13.11 + <4><5> <6> <7>
13.12 + <4><5> <6> <7>
13.13 + ...
13.14 + <4><5> <6> <7>
13.15 +
13.16 +1: Classname
13.17 +2: VTable Offset
13.18 +3: Linux This Pointer Offset
13.19 +4: "T" if the function is a MI thunk
13.20 +5: Linux VTable Index
13.21 +6: Windows VTable Index
13.22 +7: Function Signature
13.23 +"""
13.24 +
13.25 +catchclass = False
13.26 +innerclass = ""
13.27 +
13.28 +classname = None
13.29 +offsetdata = {}
13.30 +
13.31 +def ExtractTypeInfo(ea, level = 0):
13.32 + global catchclass
13.33 + global innerclass
13.34 + global classname
13.35 + global offsetdata
13.36 +
13.37 + # Param needed to support old IDAPython versions
13.38 + end = NextHead(ea, 4294967295)
13.39 +
13.40 + # Skip vtable
13.41 + ea += 4
13.42 +
13.43 + # Get type name
13.44 + name = Demangle("_Z" + GetString(Dword(ea)), GetLongPrm(INF_LONG_DN))
13.45 + ea += 4
13.46 +
13.47 + if classname is None and level == 0:
13.48 + classname = name
13.49 +
13.50 + if catchclass:
13.51 + innerclass = name
13.52 + catchclass = False
13.53 +
13.54 + print "%*s%s" % (level, "", name)
13.55 +
13.56 + if not ea < end: # Base Type
13.57 + pass
13.58 + elif isData(GetFlags(Dword(ea))): # Single Inheritance
13.59 + ExtractTypeInfo(Dword(ea), level + 1)
13.60 + ea += 4
13.61 + else: # Multiple Inheritance
13.62 + ea += 8
13.63 + while ea < end:
13.64 + catchclass = True
13.65 + ExtractTypeInfo(Dword(ea), level + 1)
13.66 + ea += 4
13.67 + offset = Dword(ea)
13.68 + ea += 4
13.69 + #print "%*s Offset: 0x%06X" % (level, "", offset >> 8)
13.70 + if (offset >> 8) != 0:
13.71 + offsetdata[offset >> 8] = innerclass
13.72 +
13.73 +# Source: http://stackoverflow.com/a/9147327
13.74 +def twos_comp(val, bits):
13.75 + """compute the 2's compliment of int value val"""
13.76 + if (val & (1 << (bits - 1))) != 0:
13.77 + val = val - (1 << bits)
13.78 + return val
13.79 +
13.80 def Analyze():
13.81 SetStatus(IDA_STATUS_WORK)
13.82
13.83 @@ -29,7 +102,8 @@
13.84 ea = ScreenEA()
13.85
13.86 if not isHead(GetFlags(ea)):
13.87 - ea = PrevHead(ea)
13.88 + # Param needed to support old IDAPython versions
13.89 + ea = PrevHead(ea, 0)
13.90
13.91 # Param needed to support old IDAPython versions
13.92 end = NextHead(ea, 4294967295)
13.93 @@ -43,18 +117,23 @@
13.94 linux_vtable = []
13.95 temp_windows_vtable = []
13.96
13.97 + other_linux_vtables = {}
13.98 + other_thunk_linux_vtables = {}
13.99 + temp_other_windows_vtables = {}
13.100 +
13.101 # Extract vtable
13.102 while ea < end:
13.103 - offset = Dword(ea)
13.104 + # Read thisoffs
13.105 + offset = -twos_comp(Dword(ea), 32)
13.106 + ea += 4
13.107
13.108 - # A vtable starts with some metadata, if it's missing...
13.109 - if isCode(GetFlags(offset)):
13.110 - Warning("Something went wrong!")
13.111 - SetStatus(IDA_STATUS_READY)
13.112 - return
13.113 + # Read typeinfo address
13.114 + typeinfo = Dword(ea)
13.115 + ea += 4
13.116
13.117 - # Skip thisoffs and typeinfo address
13.118 - ea += 8
13.119 + if offset == 0: # We only need to read this once
13.120 + print "Inheritance Tree:"
13.121 + ExtractTypeInfo(typeinfo)
13.122
13.123 while ea < end and isCode(GetFlags(Dword(ea))):
13.124 name = Demangle(Name(Dword(ea)), GetLongPrm(INF_LONG_DN))
13.125 @@ -63,9 +142,22 @@
13.126 linux_vtable.append(name)
13.127 temp_windows_vtable.append(name)
13.128 else:
13.129 + if offset not in other_linux_vtables:
13.130 + other_linux_vtables[offset] = []
13.131 + temp_other_windows_vtables[offset] = []
13.132 + other_thunk_linux_vtables[offset] = []
13.133 +
13.134 + if "`non-virtual thunk to'" in name:
13.135 + other_linux_vtables[offset].append(name[22:])
13.136 + other_thunk_linux_vtables[offset].append(name[22:])
13.137 + temp_other_windows_vtables[offset].append(name[22:])
13.138 + else:
13.139 + other_linux_vtables[offset].append(name)
13.140 + temp_other_windows_vtables[offset].append(name)
13.141 +
13.142 # MI entry, strip "`non-virtual thunk to'" and remove from list
13.143 # But not if it's a dtor... what the hell is this.
13.144 - if (name.find("`non-virtual thunk to'") != -1) and name.find("::~") == -1:
13.145 + if "`non-virtual thunk to'" in name and "::~" not in name:
13.146 name = name[22:]
13.147 #print "Stripping '%s' from windows vtable." % (name)
13.148 temp_windows_vtable.remove(name)
13.149 @@ -73,7 +165,7 @@
13.150 ea += 4
13.151
13.152 for i, v in enumerate(temp_windows_vtable):
13.153 - if v.find("::~") != -1:
13.154 + if "::~" in v:
13.155 #print "Found destructor at index %d: %s" % (i, v)
13.156 del temp_windows_vtable[i]
13.157 break
13.158 @@ -96,16 +188,19 @@
13.159 overload_stack.append(v)
13.160 else:
13.161 # If we've moved onto something new, dump the stack first
13.162 - if len(overload_stack) > 0:
13.163 - #print overload_stack
13.164 - while len(overload_stack) > 0:
13.165 - windows_vtable.append(overload_stack.pop())
13.166 + while len(overload_stack) > 0:
13.167 + windows_vtable.append(overload_stack.pop())
13.168
13.169 windows_vtable.append(v)
13.170
13.171 prev_function = function
13.172 prev_symbol = v
13.173
13.174 + # If there is anything left in the stack, dump it
13.175 + while len(overload_stack) > 0:
13.176 + windows_vtable.append(overload_stack.pop())
13.177 +
13.178 + print "\nVTable for %s: (0, 0)" % (classname)
13.179 print "Lin Win Function"
13.180 for i, v in enumerate(linux_vtable):
13.181 winindex = windows_vtable.index(v) if v in windows_vtable else None
13.182 @@ -114,7 +209,45 @@
13.183 else:
13.184 print "%3d %s" % (i, v)
13.185
13.186 + for k in temp_other_windows_vtables:
13.187 + for i, v in enumerate(temp_other_windows_vtables[k]):
13.188 + if v.find("::~") != -1:
13.189 + #print "Found destructor at index %d: %s" % (i, v)
13.190 + del temp_other_windows_vtables[k][i]
13.191 + break
13.192 +
13.193 + other_windows_vtables = {}
13.194 + for k in temp_other_windows_vtables:
13.195 + other_windows_vtables[k] = []
13.196 + overload_stack = []
13.197 + prev_function = ""
13.198 + prev_symbol = ""
13.199 + for v in temp_other_windows_vtables[k]:
13.200 + function = v.split("(", 1)[0]
13.201 + if function == prev_function:
13.202 + if len(overload_stack) == 0:
13.203 + other_windows_vtables[k].pop()
13.204 + overload_stack.append(prev_symbol)
13.205 + overload_stack.append(v)
13.206 + else:
13.207 + if len(overload_stack) > 0:
13.208 + while len(overload_stack) > 0:
13.209 + other_windows_vtables[k].append(overload_stack.pop())
13.210 + other_windows_vtables[k].append(v)
13.211 + prev_function = function
13.212 + prev_symbol = v
13.213 +
13.214 + for k in other_linux_vtables:
13.215 + print "\nVTable for %s: (%d, %d)" % (offsetdata[k], offsetdata.keys().index(k) + 1, k)
13.216 + print "Lin Win Function"
13.217 + for i, v in enumerate(other_linux_vtables[k]):
13.218 + winindex = other_windows_vtables[k].index(v)
13.219 + if v not in other_thunk_linux_vtables[k]:
13.220 + print "%3d %3d %s" % (i, winindex, v)
13.221 + else:
13.222 + print "T%2d %3d %s" % (i, winindex, v)
13.223 +
13.224 SetStatus(IDA_STATUS_READY)
13.225
13.226 if __name__ == '__main__':
13.227 - Analyze()
13.228 \ No newline at end of file
13.229 + Analyze()