解决 Zend Studio for Eclipse 6.x.x 启动时的 bug
Posted by dengwei
在 Zend Studio for Eclipse 时会有显示 Building PHP Project 的错误,解决的办法很简单,在 preference 里的 General 中设置 Startup and Shutdown ,把 Advanced Debugger UI Plug-in 和 PDT Debug Daemon Plug-in 的对号去掉既可。
终于找到在 firefox 下替代 httpwatch 的软件了, httpfox
Posted by dengwei
一直不放弃 ie 就在 ff 上没有找到哪几个插件能代替我的无敌 debug 组合 debugbar + compain.JS + httpwatch + iedevtoolbar
现在可以用 firebug + httpwatch + yslow + web developer 来取代 ie 了,太爽了 httpfox 还是免费的,哈。
httpwatch
[分享] 某知名手机平台的XML Parser源代码
Posted by gavinkwoe
今天心情不错~ 分享一下小弟06年在某手机公司写的XML parser.
虽然当时脑子里还没有FSM的概念, 但代码逻辑还算清晰, 颇有成就感!
结构比较简单, 按DOM方式把指定文件解析成节点树, 另外提供几个简单的查找函数.
部分功能等完善, 过段时间再发一份功能比较完善的C++版本.
PLX_XMLParser.h
#if _MSC_VER > 1000
#pragma once
#endif
#ifndef __XMLPARSE_H
#define __XMLPARSE_H
#include
//////////////////////////////
// Configure
#define USE_INLINE_FUNCTION
#define USE_FILEBUFFER
//////////////////////////////
// Constants
typedef enum {
XMLERR_OK = 0×0,
XMLERR_EFILE, // failed to open file
XMLERR_ALRDOPEN, // already opened
XMLERR_EDOC,
XMLERR_EPARSE,
} XMLERR;
typedef enum {
NODETYPE_UNKN = 0×0,
NODETYPE_ELEM = 0×1,
NODETYPE_TEXT = 0×2,
NODETYPE_COMM = 0×4,
NODETYPE_INST = 0×8, // Not support
//NODETYPE_USEFUL = NODETYPE_ELEM|NODETYPE_TEXT,
//NODETYPE_ALL = NODETYPE_ELEM|NODETYPE_TEXT|NODETYPE_COMM|NODETYPE_INST,
} NODETYPE;
typedef enum {
DSTAT_UNOPEN = 0×0,
DSTAT_OPENED = 0×1,
} DOCSTAT;
typedef enum {
ISTAT_STOP = 0×0,
ISTAT_CONTINUE = 0×1,
ISTAT_PASS = 0×2,
} ITERSTAT;
enum { MAXLEN_BSTR = 256 };
//////////////////////////////
// Structures
struct tagBString
{
LONG m_lLength;
union {
CHAR m_paStr[1];
LPCSTR m_pszStr;
};
};
typedef struct tagBString BSTRING;
typedef struct tagBString *LPBSTRING;
typedef struct tagBString const *LPCBSTRING;
struct tagXMLAttrib;
typedef struct tagXMLAttrib XMLATTRIB;
typedef struct tagXMLAttrib *LPXMLATTRIB;
typedef struct tagXMLAttrib const *LPCXMLATTRIB;
struct tagXMLAttrib
{
LPBSTRING m_pbstrName;
LPBSTRING m_pbstrValue;
LPXMLATTRIB m_pNext;
};
struct tagXMLNode;
typedef struct tagXMLNode XMLNODE;
typedef struct tagXMLNode *LPXMLNODE;
typedef struct tagXMLNode const *LPCXMLNODE;
struct tagXMLNode
{
NODETYPE m_eNodeType;
LONG m_lDepth;
LPBSTRING m_pbstrTag;
LONG m_lChildNum;
LONG m_lChildNum_Elem;
LPXMLNODE m_pRoot;
LPXMLNODE m_pParent;
LPXMLNODE m_pFirstChild;
LPXMLNODE m_pLastChild;
LPXMLNODE m_pPrevSibling;
LPXMLNODE m_pNextSibling;
LONG m_lAttribNum;
LPXMLATTRIB m_pFirstAttrib;
};
struct tagXMLDocument
{
DOCSTAT m_eDocStat;
LPXMLNODE m_lpRootNode;
};
typedef struct tagXMLDocument XMLDOCUMENT;
typedef struct tagXMLDocument *LPXMLDOCUMENT;
typedef struct tagXMLDocument const *LPCXMLDOCUMENT;
//////////////////////////////
// Types
typedef ITERSTAT (CALLBACK *LPFNNODEPROC)( LPCXMLNODE pNode, LPVOID pvParam );
//////////////////////////////
// Macros
#if defined(USE_INLINE_FUNCTION)
#define BSTR_C( pBStr ) (&((pBStr)->m_paStr[0]))
#define BSTR_CAST( pvAnyType ) ((LPBSTRING)pvAnyType)
#define BSTR_LEN( pBStr ) ((pBStr)->m_lLength)
#define BSTR_ALLOC( pszStr ) AllocBString( pszStr, (NULL != (pszStr) ? ((LONG)strlen(pszStr)) : (0L)) )
#define BSTR_ALLOCEX( pszStr, nLen ) AllocBString( pszStr, (LONG)nLen )
#define BSTR_FREE( pBStr ) free( pBStr )
#define BSTR_SAFEFREE( pBStr ) if ( NULL != pBStr ) { free( pBStr ); pBStr = NULL; }
#define BSTR_EQUAL( pBStrL, pBStrR ) \
( (BSTR_LEN(pBStrL) == BSTR_LEN(pBStrR) && 0 == strcmp(BSTR_C(pBStrL), BSTR_C(pBStrL))) ? \
TRUE : FALSE )
#define BSTR_EQUAL_STATIC( pBStr, szStatic ) \
( (BSTR_LEN(pBStr) == (LONG)(sizeof(szStatic) - 1) && 0 == strcmp(BSTR_C(pBStr), szStatic)) ? \
TRUE : FALSE )
#define BSTR_EQUAL_CSTR( pBStr, pszStr ) \
( (BSTR_LEN(pBStr) == (LONG)strlen(pszStr) && 0 == strcmp(BSTR_C(pBStr), pszStr)) ? \
TRUE : FALSE )
#define XML_GetRootNode( pDoc ) ((NULL == (pDoc) || (pDoc)->m_eDocStat != DSTAT_OPENED) ? NULL : (pDoc)->m_lpRootNode)
#define XML_GetNodeType( pNode ) (NULL != (pNode) ? (pNode)->m_eNodeType : NODETYPE_UNKN)
#define XML_GetNodeDepth( pNode ) (NULL != (pNode) ? (pNode)->m_lDepth : (-1L))
#define XML_GetNodeParent( pNode ) (NULL != (pNode) ? (pNode)->m_pParent : NULL)
#define XML_GetNodeFirstChild( pNode ) (NULL != (pNode) ? (pNode)->m_pFirstChild : NULL)
#define XML_GetNodeLastChild( pNode ) (NULL != (pNode) ? (pNode)->m_pLastChild : NULL)
#define XML_GetNodeChildNum( pNode ) (NULL != (pNode) ? (pNode)->m_lChildNum : (0L))
#define XML_GetNodeChildNum_Elem( pNode ) (NULL != (pNode) ? (pNode)->m_lChildNum_Elem : (0L))
#define XML_GetNodePrevSibling( pNode ) (NULL != (pNode) ? (pNode)->m_pPrevSibling : NULL)
#define XML_GetNodeNextSibling( pNode ) (NULL != (pNode) ? (pNode)->m_pNextSibling : NULL)
#define XML_GetNodeTagName( pNode ) (NULL != (pNode) ? (pNode)->m_pbstrTag : NULL)
#define XML_GetNodeAttribNum( pNode ) (NULL != (pNode) ? (pNode)->m_lAttribNum : (0L))
#define XML_GetNodeFirstAttrib( pNode ) (NULL != (pNode) ? (pNode)->m_pFirstAttrib : NULL)
#define XML_GetNodeNextAttrib( pAttr ) (NULL != (pAttr) ? (pAttr)->m_pNext : NULL)
#define XML_GetAttribValueBString( pAttr ) (NULL != (pAttr) ? (pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueCString( pAttr ) (NULL != (pAttr) ? BSTR_C((pAttr)->m_pbstrValue) : NULL)
#define XML_GetAttribValueLong( pAttr ) (NULL != (pAttr) ? (LONG)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0L))
#define XML_GetAttribValueInt( pAttr ) (NULL != (pAttr) ? (int)strtol(BSTR_C((pAttr)->m_pbstrValue), NULL, 0) : (0))
#endif
//////////////////////////////
// Function prototypes
#if defined(__cplusplus)
extern “C” {
#endif
size_t strlen_when( LPCSTR lpszStr, CHAR ch );
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet );
LPCSTR strchr_skipws( LPCSTR lpszStr );
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen );
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve );
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc );
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen );
LPXMLATTRIB XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen );
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL IncludeThis );
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam );
#if defined(__cplusplus)
} // extern “C” {
#endif
#endif // #ifndef __XMLPARSE_H
PLX_XMLParser.c
#include <assert.h>
#include <fcntl.h>
#include <io.h>
#if defined(DEBUG) || defined(_DEBUG)
#include <stdio.h>
#endif
#include “XMLParse.h”
//#pragma warning(disable:4305)
//////////////////////////////
// Configure
//#define USE_MEMORY_HEAP
#ifdef USE_FILEBUFFER // Whether use file system with os-layer buffer
#define INVALID_FILE_HANDLE ((int)-1)
#define FILE_HANDLE int
#define MODE_RDONLY (O_RDONLY)
#define FILE_OPEN(pszFile,mode) open( pszFile, mode )
#define FILE_READ(hFile,pbuf,size) read(hFile, (LPVOID)pbuf, size)
#define FILE_SEEK(hFile,off,pos) lseek( hFile, off, pos )
#define FILE_CLOSE(hFile) close( hFile )
#else
#define INVALID_FILE_HANDLE ((FILE *)NULL)
#define FILE_HANDLE FILE *
#define MODE_RDONLY (”r”)
#define FILE_OPEN(pszFile,mode) fopen( pszFile, mode )
#define FILE_READ(hFile,pbuf,size) fread((LPVOID)pbuf, size, 1, hFile)
#define FILE_SEEK(hFile,off,pos) fseek( hFile, off, pos )
#define FILE_CLOSE(hFile) fclose( hFile )
#endif
//////////////////////////////
// Constants
enum { MAXLEN_READBUF = 1024 };
typedef enum {
PSTAT_STOP = 0×0,
PSTAT_INITIAL,
PSTAT_FINAL,
PSTAT_DECL_BEG,
PSTAT_DECL_END,
PSTAT_ELEM_BEG,
PSTAT_ELEM_END,
PSTAT_TEXT_BEG,
PSTAT_TEXT_END,
PSTAT_CDATA_BEG,
PSTAT_CDATA_END,
PSTAT_COMM_BEG,
PSTAT_COMM_END,
PSTAT_ERROR,
} PARSESTAT;
//////////////////////////////
// Macros
#define ZERO_MEMORY(p, size) \
( memset((LPVOID)(p), 0×0, (size_t)size) )
#define is_WhiteSpace(ch) (((ch) == ‘ ‘ || (ch) == ‘\t’) ? TRUE : FALSE)
#define is_LineBreak(ch) (((ch) == ‘\r’ || (ch) == ‘\n’) ? TRUE : FALSE)
#define is_LeftBracket(ch) ((ch) == ‘<’ ? TRUE : FALSE)
#define is_RightBracket(ch) ((ch) == ‘>’ ? TRUE : FALSE)
#define is_BufferEmpty(ps) ((ps)->m_lReadCursor >= (ps)->m_lReadSize ? TRUE : FALSE)
#define get_BufferChar(ps) ((CHAR)((ps)->m_aReadBuf[(ps)->m_lReadCursor]))
#define is_FirstChild(pn) ((pn)->m_pPrevSibling == NULL ? TRUE : FALSE)
#define is_LastChild(pn) ((pn)->m_pNextSibling == NULL ? TRUE : FALSE)
//////////////////////////////
// Structures
struct tagXMLParseStat
{
PARSESTAT m_eParseStat;
LONG m_lDepth;
LPXMLNODE m_pRootNode;
LPXMLNODE m_pLastNode;
FILE_HANDLE m_hOpenFile;
LONG m_lFileCursor;
LONG m_lFileLength;
LONG m_lLineNo;
LONG m_lReadCursor;
LONG m_lReadSize;
BYTE m_aReadBuf[MAXLEN_READBUF];
};
typedef struct tagXMLParseStat XMLPARSESTAT;
typedef struct tagXMLParseStat *LPXMLPARSESTAT;
typedef struct tagXMLParseStat const *LPCXMLPARSESTAT;
struct tagXMLIterator
{
LONG m_lCount;
LPFNNODEPROC m_pfnProc;
LPVOID m_pvParam;
LPXMLNODE m_pStation;
};
typedef struct tagXMLIterator XMLITERFATOR;
typedef struct tagXMLIterator *LPXMLITERFATOR;
typedef struct tagXMLIterator const *LPCXMLITERFATOR;
/*struct tagMemoryPage
{
LONG lGranu ;
LONG lSize;
LPVOID pvPage;
BYTE bUseFlags[1];
};
typedef struct tagMemoryPage MEMORYPAGE;
typedef struct tagMemoryPage *LPMEMORYPAGE;
typedef struct tagMemoryPage const *LPCMEMORYPAGE;*/
//////////////////////////////
// Function prototypes
#if defined(__cplusplus)
extern “C” {
#endif
static void XML_FreeNodeTree( LPXMLNODE pNode );
static void XML_FreeAttribList( LPXMLATTRIB pAttrib );
static void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator );
static BOOL XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam );
static BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult );
static int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf );
static BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat );
static void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag );
static BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat );
static BOOL Parser_OnError( LPXMLPARSESTAT pParseStat );
//#if defined(USE_MEMORY_HEAP)
//static LPVOID MemoryHeap_Create( LONG lInitialGranu, LONG lInitialSize );
//static BOOL MemoryHeap_Destroy( LPVOID );
//static LPVOID MemoryHeap_Alloc( void );
//static void MemoryHeap_Free( LPVOID pvBlock );
//#endif
#if defined(__cplusplus)
} // extern “C” {
#endif
//////////////////////////////
// Function implementations
#if defined(__cplusplus)
extern “C” {
#endif
/*********************************************************************\
* Function: strlen_when
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_when( LPCSTR lpszStr, CHAR ch )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ch && *lpszStr != ‘\0′; lpszStr++, nLen++ )
;
return nLen;
}
/*********************************************************************\
* Function: strlen_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
size_t strlen_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
register size_t nLen;
assert( NULL != lpszStr );
for ( nLen = 0; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++, nLen++ )
;
return nLen;
}
/*********************************************************************\
* Function: strchr_notin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_notin( LPCSTR lpszStr, LPCSTR lpszSet )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && NULL == strchr(lpszSet, *lpszStr); lpszStr++ )
;
return lpszStr;
}
/*********************************************************************\
* Function: strchr_skipws
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPCSTR strchr_skipws( LPCSTR lpszStr )
{
assert( NULL != lpszStr );
for ( ; *lpszStr != ‘\0′ && is_WhiteSpace(*lpszStr); lpszStr++ )
;
return lpszStr;
}
/*********************************************************************\
* Function: AllocBString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPBSTRING AllocBString( LPCSTR lpszStr, LONG lLen )
{
LPBSTRING pBStr = (LPBSTRING)malloc( sizeof(LONG) + lLen + 1 );
assert( NULL != pBStr );
pBStr->m_lLength = lLen;
strncpy( &pBStr->m_paStr[0], lpszStr, lLen );
pBStr->m_paStr[lLen] = ‘\0′;
return pBStr;
}
/*********************************************************************\
* Function: XML_OpenDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_OpenDocument( LPXMLDOCUMENT pDoc, LPCSTR lpszFileName, DWORD dwReserve )
{
BOOL bRet;
FILE_HANDLE hFile;
XMLPARSESTAT xmlParseStat;
assert( NULL != pDoc );
assert( NULL != lpszFileName );
if ( pDoc->m_eDocStat == DSTAT_OPENED )
return XMLERR_ALRDOPEN;
ZERO_MEMORY( &xmlParseStat, sizeof(XMLPARSESTAT) );
hFile = FILE_OPEN( lpszFileName, MODE_RDONLY );
if ( INVALID_FILE_HANDLE == hFile )
return XMLERR_EFILE;
xmlParseStat.m_hOpenFile = hFile;
xmlParseStat.m_lFileCursor = 0;
xmlParseStat.m_lFileLength = FILE_SEEK( hFile, 0, SEEK_END );
FILE_SEEK( hFile, 0, SEEK_SET );
xmlParseStat.m_lDepth = 0;
xmlParseStat.m_lLineNo = 1;
bRet = Parser_RoutineStart( &xmlParseStat, pDoc );
if ( FALSE == bRet )
{
FILE_CLOSE( hFile );
return XMLERR_EPARSE;
}
pDoc->m_eDocStat = DSTAT_OPENED;
pDoc->m_lpRootNode = xmlParseStat.m_pRootNode;
FILE_CLOSE( hFile );
return XMLERR_OK;
}
/*********************************************************************\
* Function: XML_CloseDocument
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
XMLERR XML_CloseDocument( LPXMLDOCUMENT pDoc )
{
if ( NULL != pDoc && pDoc->m_eDocStat == DSTAT_OPENED )
{
XML_FreeNodeTree( pDoc->m_lpRootNode );
pDoc->m_lpRootNode = NULL;
pDoc->m_eDocStat = DSTAT_UNOPEN;
}
return XMLERR_OK;
}
/*********************************************************************\
* Function: Parser_GetTagString
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
int Parser_GetTagString( LPXMLPARSESTAT pParseStat, LPSTR lpszBuf )
{
int nLen;
CHAR ch;
CHAR chTerm;
BOOL bInclude;
// Should to ensure barket match Here!
nLen = 0;
for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
goto __RET;
ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;
if ( !is_WhiteSpace(ch) && !is_LineBreak(ch) )
break;
pParseStat->m_lReadCursor++;
}
if ( is_LeftBracket(ch) )
{
chTerm = ‘>’;
bInclude = TRUE;
}
else
{
chTerm = ‘<’;
bInclude = FALSE;
}
for ( ;; )
{
if ( is_BufferEmpty(pParseStat) && FALSE == Parser_ReadStream(pParseStat) )
break;
ch = get_BufferChar(pParseStat);
if ( ch == ‘\n’ )
pParseStat->m_lLineNo++;
if ( ch == chTerm )
{
if ( FALSE != bInclude )
{
lpszBuf[nLen++] = chTerm;
pParseStat->m_lReadCursor++;
}
break;
}
lpszBuf[nLen++] = ch;
pParseStat->m_lReadCursor++;
}
__RET:
lpszBuf[nLen] = ‘\0′;
return nLen;
}
/*********************************************************************\
* Function: Parser_ReadStream
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_ReadStream( LPXMLPARSESTAT pParseStat )
{
size_t nSize;
pParseStat->m_lReadCursor = 0;
pParseStat->m_lReadSize = 0;
nSize = FILE_READ( pParseStat->m_hOpenFile, (LPVOID)&pParseStat->m_aReadBuf[0], MAXLEN_READBUF );
if ( nSize <= 0 )
return FALSE;
pParseStat->m_lReadSize = (LONG)nSize;
pParseStat->m_lFileCursor += (LONG)nSize;
return TRUE;
}
/*********************************************************************\
* Function: Parser_RoutineStart
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_RoutineStart( LPXMLPARSESTAT pParseStat, LPXMLDOCUMENT pResult )
{
BOOL bRet;
CHAR szTag[256];
assert( NULL != pParseStat );
pParseStat->m_eParseStat = PSTAT_INITIAL;
while ( pParseStat->m_eParseStat != PSTAT_STOP )
{
switch ( pParseStat->m_eParseStat )
{
case PSTAT_INITIAL: Parser_OnInitial( pParseStat, &szTag[0] ); break;
case PSTAT_DECL_BEG: Parser_OnDeclBegin( pParseStat, &szTag[0] ); break;
case PSTAT_DECL_END: Parser_OnDeclEnd( pParseStat, &szTag[0] ); break;
case PSTAT_ELEM_BEG: Parser_OnElemBegin( pParseStat, &szTag[0] ); break;
case PSTAT_ELEM_END: Parser_OnElemEnd( pParseStat, &szTag[0] ); break;
case PSTAT_TEXT_BEG: Parser_OnTextBegin( pParseStat, &szTag[0] ); break;
case PSTAT_TEXT_END: Parser_OnTextEnd( pParseStat, &szTag[0] ); break;
case PSTAT_CDATA_BEG: Parser_OnCDATABegin( pParseStat, &szTag[0] ); break;
case PSTAT_CDATA_END: Parser_OnCDATAEnd( pParseStat, &szTag[0] ); break;
case PSTAT_COMM_BEG: Parser_OnCommBegin( pParseStat, &szTag[0] ); break;
case PSTAT_COMM_END: Parser_OnCommEnd( pParseStat, &szTag[0] ); break;
case PSTAT_FINAL: bRet = Parser_OnFinal( pParseStat ); break;
case PSTAT_ERROR: bRet = Parser_OnError( pParseStat ); break;
default:
assert( !”Unknown parsing status!” );
break;
}
}
return bRet;
}
/*********************************************************************\
* Function: Parser_OnInitial
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnInitial( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLen;
assert( NULL != lpszTag );
lpszTag[0] = ‘\0′;
nLen = Parser_GetTagString( pParseStat, lpszTag );
if ( nLen <= 0 )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return;
}
if ( lpszTag[0] == ‘<’ )
{
if ( lpszTag[1] == ‘?’)
{
pParseStat->m_eParseStat = PSTAT_DECL_BEG;
}
else if ( !strncmp(&lpszTag[1], “!–”, 3) )
{
pParseStat->m_eParseStat = PSTAT_COMM_BEG;
}
else if ( lpszTag[1] == ‘/’ )
{
pParseStat->m_eParseStat = PSTAT_ELEM_END;
}
else if ( isalpha(lpszTag[1]) )
{
pParseStat->m_eParseStat = PSTAT_ELEM_BEG;
}
else if ( !strncmp(&lpszTag[1], “![CDATA[", 8) )
{
pParseStat->m_eParseStat = PSTAT_CDATA_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}
else if ( NULL != pParseStat->m_pLastNode )
{
pParseStat->m_eParseStat = PSTAT_TEXT_BEG;
}
else
{
pParseStat->m_eParseStat = PSTAT_ERROR;
}
}
/*********************************************************************\
* Function: Parser_OnFinal
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnFinal( LPXMLPARSESTAT pParseStat )
{
pParseStat->m_eParseStat = PSTAT_STOP;
return TRUE;
}
/*********************************************************************\
* Function: Parser_OnError
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
BOOL Parser_OnError( LPXMLPARSESTAT pParseStat )
{
XML_FreeNodeTree( pParseStat->m_pRootNode );
pParseStat->m_pRootNode = NULL;
pParseStat->m_eParseStat = PSTAT_STOP;
TRACE( "[Xml Parser]: Syntax error @ %s #%ld.\n”, “”, pParseStat->m_lLineNo);
return FALSE;
}
/*********************************************************************\
* Function: Parser_OnDeclBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLenTag;
if ( NULL != pParseStat->m_pRootNode )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}
lpszTag = (LPSTR)strchr_skipws( (LPCSTR)(lpszTag + 2) );
if ( lpszTag == ‘\0′ )
{
pParseStat->m_eParseStat = PSTAT_ERROR;
return;
}
nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag == 3 && !strncmp(lpszTag, “xml”, 3) )
{
// Here, dispose version and coding infomation in XML document header
}
else if ( nLenTag == 14 && !strncmp(lpszTag, “xml-stylesheet”, 3) )
{
// Unsupport
}
else
{
// Unknown declaretion
}
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnDeclEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnDeclEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Do noting
}
/*********************************************************************\
* Function: Parser_OnElemBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
int nLenTag;
int nLenValue;
LPSTR lpszValue;
LPXMLNODE pNode;
LPXMLATTRIB pAttrib;
LPXMLATTRIB pPrevAttr;
assert( is_LeftBracket(lpszTag[0]) );
// Multi-root node is not supproted
if ( 0 == pParseStat->m_lDepth && NULL != pParseStat->m_pRootNode )
goto __ERROR;
pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pNode )
goto __ERROR;
ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType = NODETYPE_ELEM;
pNode->m_lDepth = pParseStat->m_lDepth;
if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth ) // new child
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth ) // new sibling
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}
if ( NULL != pNode->m_pParent )
{
pNode->m_pParent->m_lChildNum++;
pNode->m_pParent->m_lChildNum_Elem++;
}
}
if ( NULL == pParseStat->m_pRootNode )
{
pParseStat->m_pRootNode = pNode;
}
pNode->m_pRoot = pParseStat->m_pRootNode;
pParseStat->m_pLastNode = pNode;
lpszTag++;
nLenTag = (int)strlen_notin(lpszTag, ” \t\r\n>”);
if ( nLenTag <= 0 )
goto __ERROR;
pNode->m_pbstrTag = BSTR_ALLOCEX(lpszTag, nLenTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;
lpszTag = (LPSTR)(lpszTag + nLenTag);
for ( pPrevAttr = NULL;; )
{
lpszTag = (LPSTR)strchr_skipws( lpszTag );
if ( is_RightBracket(*lpszTag) )
{
pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}
else if ( !strncmp(lpszTag, “/>”, 2) )
{
//pParseStat->m_lDepth–; //
pParseStat->m_eParseStat = PSTAT_INITIAL;
break;
}
nLenTag = (int)strlen_when( lpszTag, ‘=’ );
if ( nLenTag <= 0 )
goto __ERROR;
lpszValue = strchr( (LPCSTR)(lpszTag + nLenTag), ‘\”‘ );
if ( NULL == lpszValue )
goto __ERROR;
lpszValue++;
nLenValue = (int)strlen_when( lpszValue, ‘\”‘ );
//if ( nLenValue <= 0 )
// goto __ERROR;
pAttrib = (LPXMLATTRIB)malloc(sizeof(XMLATTRIB));
if ( NULL == pAttrib )
goto __ERROR;
ZERO_MEMORY( pAttrib, sizeof(XMLATTRIB) );
pAttrib->m_pbstrName = BSTR_ALLOCEX( lpszTag, nLenTag );
pAttrib->m_pbstrValue = BSTR_ALLOCEX( lpszValue, nLenValue );
if ( NULL == pAttrib->m_pbstrName || NULL == pAttrib->m_pbstrValue )
goto __ERROR;
if ( NULL == pNode->m_pFirstAttrib )
pNode->m_pFirstAttrib = pAttrib;
if ( NULL != pPrevAttr )
pPrevAttr->m_pNext = pAttrib;
pPrevAttr = pAttrib;
pNode->m_lAttribNum++;
lpszTag = lpszValue + nLenValue + 1;
}
return;
__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}
/*********************************************************************\
* Function: Parser_OnElemEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnElemEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_lDepth–;
if ( NULL != pParseStat->m_pLastNode )
{
if ( NULL != pParseStat->m_pLastNode->m_pParent )
pParseStat->m_pLastNode->m_pParent->m_pLastChild = pParseStat->m_pLastNode;
if ( pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;
}
if ( 0 == pParseStat->m_lDepth )
pParseStat->m_eParseStat = PSTAT_FINAL;
else
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnTextBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
LPXMLNODE pNode;
pNode = (LPXMLNODE)malloc(sizeof(XMLNODE));
if ( NULL == pParseStat->m_pLastNode )
goto __ERROR;
ZERO_MEMORY( pNode, sizeof(XMLNODE) );
pNode->m_eNodeType = NODETYPE_TEXT;
pNode->m_lDepth = pParseStat->m_lDepth;
if ( NULL != pParseStat->m_pLastNode )
{
assert( pNode->m_lDepth >= pParseStat->m_pLastNode->m_lDepth );
if ( pNode->m_lDepth > pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode;
pParseStat->m_pLastNode->m_pFirstChild = pNode;
}
else if ( pNode->m_lDepth == pParseStat->m_pLastNode->m_lDepth )
{
pNode->m_pParent = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_pLastNode->m_pNextSibling = pNode;
pNode->m_pPrevSibling = pParseStat->m_pLastNode;
}
if ( NULL != pNode->m_pParent )
pNode->m_pParent->m_lChildNum++;
pNode->m_pRoot = pParseStat->m_pLastNode->m_pRoot;
}
pParseStat->m_pLastNode = pNode;
pNode->m_pbstrTag = BSTR_ALLOC(lpszTag);
if ( NULL == pNode->m_pbstrTag )
goto __ERROR;
pParseStat->m_lDepth++; // Move down one layer
pParseStat->m_eParseStat = PSTAT_TEXT_END;
return;
__ERROR:
XML_FreeNodeTree( pNode );
pParseStat->m_eParseStat = PSTAT_ERROR;
}
/*********************************************************************\
* Function: Parser_OnTextEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnTextEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
// Move up one layer
pParseStat->m_lDepth–;
if ( NULL != pParseStat->m_pLastNode &&
pParseStat->m_pLastNode->m_lDepth > pParseStat->m_lDepth )
pParseStat->m_pLastNode = pParseStat->m_pLastNode->m_pParent;
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnCommBegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommBegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
}
/*********************************************************************\
* Function: Parser_OnCommEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCommEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}
/*********************************************************************\
* Function: Parser_OnCDATABegin
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATABegin( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
pParseStat->m_eParseStat = PSTAT_INITIAL;
// Should convert to text here
}
/*********************************************************************\
* Function: Parser_OnCDATAEnd
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void Parser_OnCDATAEnd( LPXMLPARSESTAT pParseStat, LPSTR lpszTag )
{
}
/*********************************************************************\
* Function: XML_IterateTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_IterateTree( LPXMLNODE pTree, LPXMLITERFATOR pIterator )
{
register ITERSTAT eStat;
if ( NULL != pTree )
{
pIterator->m_pStation = pTree;
eStat = pIterator->m_pfnProc( pTree, pIterator->m_pvParam );
if ( eStat == ISTAT_STOP )
return;
if ( eStat != ISTAT_PASS )
pIterator->m_lCount++;
XML_IterateTree( pTree->m_pFirstChild, pIterator );
XML_IterateTree( pTree->m_pNextSibling, pIterator );
}
}
/*********************************************************************\
* Function: XML_ForEachNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LONG XML_ForEachNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPFNNODEPROC pfnNodeProc, LPVOID pvParam )
{
XMLITERFATOR iter;
assert( NULL != pDoc );
assert( NULL != pfnNodeProc );
if ( pDoc->m_eDocStat == DSTAT_UNOPEN || (NULL != pStartPoint && pStartPoint->m_pRoot != pDoc->m_lpRootNode) )
return 0;
iter.m_lCount = 0;
iter.m_pStation = NULL;
iter.m_pvParam = pvParam;
iter.m_pfnProc = pfnNodeProc;
pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return iter.m_lCount;
}
/*********************************************************************\
* Function: XMLCmpNode_EqualTag
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
ITERSTAT XMLCmpNode_EqualTag( LPCXMLNODE pNode, LPVOID pvParam )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, BSTR_CAST(pvParam)) )
return ISTAT_STOP;
else
return ISTAT_CONTINUE;
}
/*********************************************************************\
* Function: XML_GetNode
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNode( LPXMLDOCUMENT pDoc, LPXMLNODE pStartPoint, LPCSTR lpszTag, LONG lLen )
{
BSTRING bStr;
XMLITERFATOR iter;
assert( NULL != lpszTag );
assert( NULL != pDoc );
if ( pDoc->m_eDocStat == DSTAT_UNOPEN || pStartPoint->m_pRoot != pDoc->m_lpRootNode )
return NULL;
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszTag;
iter.m_lCount = 0;
iter.m_pfnProc = &XMLCmpNode_EqualTag;
iter.m_pStation = NULL;
iter.m_pvParam = (LPVOID)&bStr;
pStartPoint = (NULL == pStartPoint ? pDoc->m_lpRootNode : pStartPoint);
XML_IterateTree( pStartPoint, &iter );
return (iter.m_pStation);
}
/*********************************************************************\
* Function: XML_GetNodeAttrib
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLATTRIB XML_GetNodeAttrib( LPXMLNODE pNode, LPCSTR lpszAttr, LONG lLen )
{
BSTRING bStr;
LPXMLATTRIB pAttrib;
assert( NULL != lpszAttr );
assert( NULL != pNode );
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszAttr;
for ( pAttrib = XML_GetNodeFirstAttrib(pNode); NULL != pAttrib; pAttrib = XML_GetNodeNextAttrib(pAttrib) )
{
if ( FALSE != BSTR_EQUAL(pAttrib->m_pbstrName, &bStr) )
break;
}
return pAttrib;
}
/*********************************************************************\
* Function: XML_GetNodeSibling
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
LPXMLNODE XML_GetNodeSibling( LPXMLNODE pNode, LPCSTR lpszTag, LONG lLen, BOOL bIncludeThis )
{
BSTRING bStr;
assert( NULL != lpszTag );
assert( NULL != pNode );
bStr.m_lLength = lLen;
bStr.m_pszStr = lpszTag;
if ( FALSE != bIncludeThis && FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
return pNode;
for ( pNode = XML_GetNodeNextSibling(pNode); NULL != pNode; pNode = XML_GetNodeNextSibling(pNode) )
{
if ( FALSE != BSTR_EQUAL(pNode->m_pbstrTag, &bStr) )
break;
}
return pNode;
}
/*********************************************************************\
* Function: XML_FreeNodeTree
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeNodeTree( LPXMLNODE pNode )
{
if ( NULL != pNode )
{
BSTR_FREE( pNode->m_pbstrTag );
XML_FreeAttribList( pNode->m_pFirstAttrib );
if ( is_FirstChild(pNode) && NULL != pNode->m_pParent )
pNode->m_pParent->m_pFirstChild = pNode->m_pNextSibling;
if ( NULL != pNode->m_pNextSibling )
pNode->m_pNextSibling->m_pPrevSibling = pNode->m_pPrevSibling;
if ( NULL != pNode->m_pPrevSibling )
pNode->m_pPrevSibling->m_pNextSibling = pNode->m_pNextSibling;
XML_FreeNodeTree( pNode->m_pFirstChild );
XML_FreeNodeTree( pNode->m_pNextSibling );
free( pNode );
}
}
/*********************************************************************\
* Function: XML_FreeAttribList
* Purpose:
* Params:
* Return
* Remarks
**********************************************************************/
void XML_FreeAttribList( LPXMLATTRIB pAttrib )
{
LPXMLATTRIB pNext;
while ( NULL != pAttrib )
{
pNext = pAttrib->m_pNext;
BSTR_FREE( pAttrib->m_pbstrName );
BSTR_FREE( pAttrib->m_pbstrValue );
free( pAttrib );
pAttrib = pNext;
}
}
#if defined(__cplusplus)
} // extern “C” {
#endif
XCache & XDebug on road
Posted by gavinkwoe
终于配置上 XCache 和 XDebug 了,可惜的是 php-java-bridge 一直没搞好,只有双击运行 JavaBridge 后才行,唉,要是能内置到 PHP 里就好了。
如果说之前在 UUSee 是向上研究,既“抽象”、“架构”的话,那么来 IMobile 之后研究方向则是向下,研究底层,研究以前没注意到的更细节的地方了。
:)
Good days, good luck.
[超长篇] Inject Your Code to a Portable Executable File
Posted by dengwei
转至: http://www.codeguru.com/cpp/w-p/system/misc/article.php/c11393
Downloads
Windows NT 3.51 (I mean, Win3.1, Win95, Win98 were not perfect OSs). The MS-DOS data causes that your executable file to have the performance inside MS-DOS and the MS-DOS Stub program lets it display: "This program can not be run in MS-DOS mode" or "This program can be run only in Windows mode", or some things like these comments when you try to run a Windows EXE file inside MS-DOS 6.0, where there is no footstep of Windows. Thus, this data is reserved for the code to indicate these comments in the MS-DOS operating system. The most interesting part of the MS-DOS data is "MZ"! Can you believe, it refers to the name of "Mark Zbikowski", one of the first Microsoft programmers?
0 Preface
You might demand to comprehend the ways a virus program injects its procedure into the interior of a portable executable file and corrupts it, or you are interested in implementing a packer or a protector to encrypt the data of your portable executable (PE) file. This article is committed to represent a brief discussion to realize the performance that is accomplished by EXE tools or some kinds of mal-ware.
You can employ this article’s source code to create your custom EXE builder. It could be used to make an EXE protector in the right way, or with the wrong intention, to spread a virus. However, my purpose of writing this article has been the first application, so I will not be responsible for the immoral usage of these methods.
1 Prerequisites
There are no specific mandatory prerequisites to follow the topics in this article. If you are familiar with a debugger and also the portable file format, I suggest you to drop to Sections 2 and 3; the whole of these sections has been made for people who don’t have any knowledge regarding the EXE file format or debuggers.
2 Portable Executable File Format
The Portable Executable file format was defined to provide the best way for the Windows Operating System to execute code and also to store the essential data that is needed to run a program—for example constant data, variable data, import library links, and resource data. It consists of MS-DOS file information, Windows NT file information, Section Headers, and Section images, as shown in Table 1.
2.1 The MS-DOS data
These data let you remember the first days of developing the Windows Operating System. You were at the beginning of a way to achieve a complete Operating System such as
To me, only the offset of the PE signature in the MS-DOS data is important, so I can use it to find the position of the Windows NT data. I just recommend that you take a look at Table 1, and then observe the structure of IMAGE_DOS_HEADER in the <winnt.h> header in the <Microsoft Visual Studio .net path>\VC7\PlatformSDK\include\ folder or the <Microsoft Visual Studio 6.0 path>\VC98\include\ folder. I do not know why the Microsoft team has forgotten to provide some comment about this structure in the MSDN library!
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header "MZ" WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in // paragraphs WORD e_minalloc; // Minimum extra paragraphs // needed WORD e_maxalloc; // Maximum extra paragraphs // needed WORD e_ss; // Initial (relative) SS // value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS // value WORD e_lfarlc; // File address of relocation // table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier // (for e_oeminfo) WORD e_oeminfo; // OEM information; // e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of the new // exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
e_lfanew is the offset that refers to the position of the Windows NT data. I have provided a program to obtain the header information from an EXE file and to display it to you. To use the program, just try:
PE Viewer
This sample is useful for the whole of this article.
Table 1: Portable Executable file format structure
| MS-DOS information |
IMAGE_DOS_ HEADER |
DOS EXE Signature |
00000000 ASCII "MZ"00000002 DW 009000000004 DW 000300000006 DW 000000000008 DW 00040000000A DW 00000000000C DW FFFF0000000E DW 000000000010 DW 00B800000012 DW 000000000014 DW 000000000016 DW 000000000018 DW 00400000001A DW 00000000001C DB 00b&b&0000003B DB 000000003C DD 000000F0
|
| DOS_PartPag | |||
| DOS_PageCnt | |||
| DOS_ReloCnt | |||
| DOS_HdrSize | |||
| DOS_MinMem | |||
| DOS_MaxMem | |||
| DOS_ReloSS | |||
| DOS_ExeSP | |||
| DOS_ChkSum | |||
| DOS_ExeIPP | |||
| DOS_ReloCS | |||
| DOS_TablOff | |||
| DOS_Overlay | |||
| b& Reserved words b& |
|||
| Offset to PE signature | |||
| MS-DOS Stub Program |
00000040 ..B:..B4.C!B8\LC!This program canno00000060 t be run in DOS mode....$.......
|
||
| Windows NT information IMAGE_ |
Signature | PE signature (PE) |
000000F0 ASCII "PE"
|
| IMAGE_ FILE_HEADER |
Machine |
000000F4 DW 014C000000F6 DW 0003000000F8 DD 3B7D8410000000FC DD 0000000000000100 DD 0000000000000104 DW 00E000000106 DW 010F
|
|
| NumberOfSections | |||
| TimeDateStamp | |||
| PointerToSymbolTable | |||
| NumberOfSymbols | |||
| SizeOfOptionalHeader | |||
| Characteristics | |||
| IMAGE_ OPTIONAL_ HEADER32 |
MagicNumber |
00000108 DW 010B0000010A DB 070000010B DB 000000010C DD 0001280000000110 DD 00009C0000000114 DD 0000000000000118 DD 000124750000011C DD 0000100000000120 DD 0001400000000124 DD 0100000000000128 DD 000010000000012C DD 0000020000000130 DW 000500000132 DW 000100000134 DW 000500000136 DW 000100000138 DW 00040000013A DW 00000000013C DD 0000000000000140 DD 0001F00000000144 DD 0000040000000148 DD 0001D7FC0000014C DW 00020000014E DW 800000000150 DD 0004000000000154 DD 0000100000000158 DD 001000000000015C DD 0000100000000160 DD 0000000000000164 DD 00000010
|
|
| MajorLinkerVersion | |||
| MinorLinkerVersion | |||
| SizeOfCode | |||
| SizeOfInitializedData | |||
| SizeOfUninitializedData | |||
| AddressOfEntryPoint | |||
| BaseOfCode | |||
| BaseOfData | |||
| ImageBase | |||
| SectionAlignment | |||
| FileAlignment | |||
| MajorOSVersion | |||
| MinorOSVersion | |||
| MajorImageVersion | |||
| MinorImageVersion | |||
| MajorSubsystemVersion | |||
| MinorSubsystemVersion | |||
| Reserved | |||
| SizeOfImage | |||
| SizeOfHeaders | |||
| CheckSum | |||
| Subsystem | |||
| DLLCharacteristics | |||
| SizeOfStackReserve | |||
| SizeOfStackCommit | |||
| SizeOfHeapReserve | |||
| SizeOfHeapCommit | |||
| LoaderFlags | |||
| NumberOfRvaAndSizes | |||
| IMAGE_ DATA_DIRECTORY[16] |
Export Table | ||
| Import Table | |||
| Resource Table | |||
| Exception Table | |||
| Certificate File | |||
| Relocation Table | |||
| Debug Data | |||
| Architecture Data | |||
| Global Ptr | |||
| TLS Table | |||
| Load Config Table | |||
| Bound Import Table | |||
| Import Address Table | |||
| Delay Import Descriptor | |||
| COM+ Runtime Header | |||
| Reserved | |||
| Sections information |
IMAGE_ SECTION_ HEADER[0] |
Name[8] |
000001E8 ASCII".text"000001F0 DD 000126B0000001F4 DD 00001000000001F8 DD 00012800000001FC DD 0000040000000200 DD 0000000000000204 DD 0000000000000208 DW 00000000020A DW 00000000020C DD 60000020 CODE|EXECUTE|READ
|
| VirtualSize | |||
| VirtualAddress | |||
| SizeOfRawData | |||
| PointerToRawData | |||
| PointerToRelocations | |||
| PointerToLineNumbers | |||
| NumberOfRelocations | |||
| NumberOfLineNumbers | |||
| Characteristics | |||
| b& b& b& IMAGE_ SECTION_ HEADER[n] |
00000210 ASCII".data"; SECTION00000218 DD 0000101C ; VirtualSize = 0x101C0000021C DD 00014000 ; VirtualAddress = 0x1400000000220 DD 00000A00 ; SizeOfRawData = 0xA0000000224 DD 00012C00 ; PointerToRawData = 0x12C0000000228 DD 00000000 ; PointerToRelocations = 0x00000022C DD 00000000 ; PointerToLineNumbers = 0x000000230 DW 0000 ; NumberOfRelocations = 0x000000232 DW 0000 ; NumberOfLineNumbers = 0x000000234 DD C0000040 ; Characteristics = INITIALIZED_DATA|READ|WRITE00000238 ASCII".rsrc"; SECTION00000240 DD 00008960 ; VirtualSize = 0x896000000244 DD 00016000 ; VirtualAddress = 0x1600000000248 DD 00008A00 ; SizeOfRawData = 0x8A000000024C DD 00013600 ; PointerToRawData = 0x1360000000250 DD 00000000 ; PointerToRelocations = 0x000000254 DD 00000000 ; PointerToLineNumbers = 0x000000258 DW 0000 ; NumberOfRelocations = 0x00000025A DW 0000 ; NumberOfLineNumbers = 0x00000025C DD 40000040 ; Characteristics = INITIALIZED_DATA|READ
|
||
| SECTION[0] |
00000400 EA 22 DD 77 D7 23 DD 77 C*"C.wC.#C.w00000408 9A 18 DD 77 00 00 00 00 E!.C.w....00000410 2E 1E C7 77 83 1D C7 77 ..C.wF..C.w00000418 FF 1E C7 77 00 00 00 00 C?.C.w....00000420 93 9F E7 77 D8 05 E8 77 b.E8C'wC..C(w00000428 FD A5 E7 77 AD A9 E9 77 C=B%C'w­B)C)w00000430 A3 36 E7 77 03 38 E7 77 B#6C'w.8C'w00000438 41 E3 E6 77 60 8D E7 77 AC#C&w`BC'w00000440 E6 1B E6 77 2B 2A E7 77 C&.C&w+*C'w00000448 7A 17 E6 77 79 C8 E6 77 z.C&wyC.C&w00000450 14 1B E7 77 C1 30 E7 77 ..C'wC.0C'wb&
|
||
| b& b& b& SECTION[n] |
b&0001BF00 63 00 2E 00 63 00 68 00 c...c.h.0001BF08 6D 00 0A 00 43 00 61 00 m...C.a.0001BF10 6C 00 63 00 75 00 6C 00 l.c.u.l.0001BF18 61 00 74 00 6F 00 72 00 a.t.o.r.0001BF20 11 00 4E 00 6F 00 74 00 ..N.o.t.0001BF28 20 00 45 00 6E 00 6F 00 .E.n.o.0001BF30 75 00 67 00 68 00 20 00 u.g.h. .0001BF38 4D 00 65 00 6D 00 6F 00 M.e.m.o.0001BF40 72 00 79 00 00 00 00 00 r.y.....0001BF48 00 00 00 00 00 00 00 00 ........0001BF50 00 00 00 00 00 00 00 00 ........0001BF58 00 00 00 00 00 00 00 00 ........0001BF60 00 00 00 00 00 00 00 00 ........0001BF68 00 00 00 00 00 00 00 00 ........0001BF70 00 00 00 00 00 00 00 00 ........0001BF78 00 00 00 00 00 00 00 00 ........
|
||
2.2 The Windows NT data
As mentioned in the preceding section, e_lfanew storage in the MS-DOS data structure refers to the location of the Windows NT information. Hence, if you assume that the pMem pointer relates the start point of the memory space for a selected portable executable file, you can retrieve the MS-DOS header and also the Windows NT headers by the following lines, which you also can perceive in the PE viewer sample (pelib.cpp, PEStructure::OpenFileName()):
IMAGE_DOS_HEADER image_dos_header;IMAGE_NT_HEADERS image_nt_headers;PCHAR pMem;b&memcpy(&image_dos_header, pMem, sizeof(IMAGE_DOS_HEADER));memcpy(&image_nt_headers, pMem+image_dos_header.e_lfanew, sizeof(IMAGE_NT_HEADERS));
IMAGE_NT_HEADERS structure definition. It makes it possible to grasp what the image NT header maintains to execute a code inside the Windows NT OS. Now, you are conversant with the Windows NT structure; it consists of the "PE" Signature, the File Header, and the Optional Header. Do not forget to take a glimpse at their comments in the MSDN Library and in Table 1.
It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDN library regarding the
One the whole, I consider merely, in most circumstances, the following cells of the IMAGE_NT_HEADERS structure:
FileHeader->NumberOfSectionsOptionalHeader->AddressOfEntryPointOptionalHeader->ImageBaseOptionalHeader->SectionAlignmentOptionalHeader->FileAlignmentOptionalHeader->SizeOfImageOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] ->VirtualAddressOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] ->Size
You can observe the main purpose of these values clearly, and their role when the internal virtual memory space allocated for an EXE file by the Windows task manager if you pay attention to their explanations in MSDN library, so I am not going to repeat the MSDN annotations here.
I should make a brief comment regarding the PE data directories, or OptionalHeader-> DataDirectory[], because I think there are a few aspects of interest concerning them. When you come to survey the Optional header through the Windows NT information, you will find that there are 16 directories at the end of the Optional Header, where you can find the consecutive directories, including their Relative Virtual Address and Size. I just mention here the notes from <winnt.h> to clarify these information:
// Export Directory#define IMAGE_DIRECTORY_ENTRY_EXPORT 0// Import Directory#define IMAGE_DIRECTORY_ENTRY_IMPORT 1// Resource Directory#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2// Exception Directory#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3// Security Directory#define IMAGE_DIRECTORY_ENTRY_SECURITY 4// Base Relocation Table#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5// Debug Directory#define IMAGE_DIRECTORY_ENTRY_DEBUG 6// Architecture Specific Data#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7// RVA of GP#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8// TLS Directory#define IMAGE_DIRECTORY_ENTRY_TLS 9// Load Configuration Directory#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10// Bound Import Directory in headers#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11// Import Address Table#define IMAGE_DIRECTORY_ENTRY_IAT 12// Delay Load Import Descriptors#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13// COM Runtime descriptor#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
The last one (15) was reserved for use in the future; I have not yet seen any purpose for it, even in PE64.
For instance, if you want to perceive the relative virtual address (RVA) and the size of the resource data, it is enough to retrieve them by:
DWORD dwRVA = image_nt_headers.OptionalHeader-> DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->VirtualAddress;DWORD dwSize = image_nt_headers.OptionalHeader-> DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->Size;
To comprehend more regarding the significance of data directories, I forward you to Section 3.4.3 of the Microsoft Portable Executable and the Common Object File Format Specification document by Microsoft, and furthermore Section 6 of this document, where you discern the various types of sections and their applications. You will see the section’s advantage subsequently.
2.3 The Section Headers and Sections
You currently observe how the portable executable files declare the location and the size of a section on a disk storage file and inside the virtual memory space allocated for the program with IMAGE_NT_HEADERS-> OptionalHeader->SizeOfImage by the Windows task manager, as well the characteristics to demonstrate the type of the section. To better understand the Section header as my previous declaration, I suggest having a brief look at the IMAGE_SECTION_HEADER structure definition in the MSDN library. For an EXE packer developer, VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, and Characteristics cells have significant rules. When developing an EXE packer, you should be clever enough to play with them. There are somet hings to note when you modify them; you should take care to align the VirtualSize and VirtualAddress according to OptionalHeader->SectionAlignment, as well as SizeOfRawData and PointerToRawData in line with OptionalHeader->FileAlignment. Otherwise, you will corrupt your target EXE file and it will never run. Regarding Characteristics, I pay attention mostly to establish a section by IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA, I prefer that my new section has the ability to initialize such data during the running process, such as import table; besides, I need it to be able to modify itself by the loader with my settings in the section characteristics to read- and writeable.
Moreover, you should pay attention to the section names; you can know the purpose of each section by its name. I will just forward you to Section 6 of the Microsoft Portable Executable and the Common Object File Format Specification documents. I believe it represents the totality of sections by their names; this is also included in Table 2.
Table 2: Section names
| ".text" | Code Section |
| "CODE" | Code Section of file linked by Borland Delphi or Borland Pascal |
| ".data" | Data Section |
| "DATA" | Data Section of file linked by Borland Delphi or Borland Pascal |
| ".rdata" | Section for Constant Data |
| ".idata" | Import Table |
| ".edata" | Export Table |
| ".tls" | TLS Table |
| ".reloc" | Relocation Information |
| ".rsrc" | Resource Information |
To comprehend the section headers and also the sections, you can run the sample PE viewer. With this PE viewer, you can realize only the application of the section headers in a file image, so to observe the main significance in the Virtual Memory, you should try to load a PE file by a debugger. The next section represents the main idea of using the virtual address and size in the virtual memory by using a debugger. The last note is about IMAGE_NT_HEADERS-> FileHeader->NumberOfSections, that provides a number of sections in a PE file. Do not forget to adjust it whenever you remove or add some sections to a PE file. I am talking about section injection!
3 Debugger, Disassembler and some Useful Tools
In this part, you will become familiar with the necessary and essential equipment to develop your PE tools.
3.1 Debuggers
The first essential prerequisite to become a PE tools developer is to have enough experience with bug tracer tools. Furthermore, you should know most of the assembly instructions. To me, the Intel documents are the best references. You can obtain them from the Intel site for IA-32, and on top of that IA-64; the future belongs to IA-64 CPUs, Windows XP 64-bit, and also PE64!
- IA-32 Intel Architecture Software Developer’s Manuals
- Intel Itanium Architecture Assembly Language Reference Guide
- The Intel Itanium Processor Developer Resource Guide
To trace a PE file, SoftICE by Compuware Corporation, I knew it also as named NuMega when I was at high school, is the best debugger in the world. It implements process tracing by using the kernel mode method debugging without applying Windows debugging application programming interface (API) functions. In addition, I will introduce one perfect debugger in user mode level. It utilizes the Windows debugging API to trace a PE file and also attaches itself to an active process. These API functions have been provided by Microsoft teams, inside the Windows Kernel32 library, to trace a specific process, by using Microsoft tools, or perhaps, to make your own debugger! Some of those API functions inlude:
- CreateThread()
- CreateProcess()
- OpenProcess()
- DebugActiveProcess()
- GetThreadContext()
- SetThreadContext()
- ContinueDebugEvent()
- DebugBreak()
- ReadProcessMemory()
- WriteProcessMemory()
- SuspendThread()
- ResumeThread()
3.1.1 SoftICE
It was in 1987; Frank Grossman and Jim Moskun decided to establish a company called NuMega Technologies in Nashua, NH, to develop some equipment to trace and test the reliability of Microsoft Windows software programs. Now, it is a part of Compuware Corporation and its product has participated to accelerate the reliability in Windows software, and additionally in Windows driver developments. Currently, everyone knows the Compuware DriverStudio that is used to establish an environment for implementing the elaboration of a kernel driver or a system file by aiding the Windows Driver Development Kit (DDK). It bypasses the involvement of DDK to implement a portable executable file of kernel level for a Windows system software developer. For us, only one instrument of DriverStudio is important, SoftICE; this debugger can be used to trace every portable executable file, a PE file for user mode level or a PE file for kernel mode level.
Figure 1: SoftICE Window
| EAX=00000000EBX=7FFDD000 ECX=0007FFB0 EDX=7C90EB94 ESI=FFFFFFFF EDI=7C919738 EBP=0007FFF0 ESP=0007FFC4 EIP=010119E0 o d i s z a p c CS=0008 DS=0023 SS=0010 ES=0023 FS=0030 GS=0000 SS:0007FFC4=87C816D4F |
| 0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ……………. 0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ……………. 0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ……..SciCalc. 0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ……..backgrou 0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd………….. |
| 0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 b.| . 0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T . 0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |…….. 0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 …. …. |
| 010119E0 PUSH EBP 010119E1 MOV EBP,ESP 010119E3 PUSH -1 010119E5 PUSH 01001570 010119EA PUSH 01011D60 010119EF MOV EAX,DWORD PTR FS:[0] 010119F5 PUSH EAX 010119F6 MOV DWORD PTR FS:[0],ESP 010119FD ADD ESP,-68 01011A00 PUSH EBX 01011A01 PUSH ESI 01011A02 PUSH EDI 01011A03 MOV DWORD PTR SS:[EBP-18],ESP 01011A06 MOV DWORD PTR SS:[EBP-4],0 |
| :_
|
3.1.2 OllyDbg
It was about four years ago that I first saw this debugger by chance. For me, it was the best choice; I was not wealthy enough to purchase SoftICE, and at that time, SoftICE only had good functions for DOS, Windows 98, and Windows 2000. I found that this debugger supported all kinds of Windows versions. Therefore, I started to learn it very fast, and now it is my favorite debugger for the Windows OS. It is a debugger that can be used to trace all kinds of portable executable files except a Common Language Infrastructure (CLI) file format in user mode level, by using the Windows debugging API. Oleh Yuschuk, the author, is one of worthiest software developers I have seen in my life. He is a Ukrainian who now lives in Germany. I should mention here that his debugger is the best choice for hacker and cracker parties around the world! It is freeware! You can try it from the OllyDbg Homepage.
Figure 2: OllyDbg CPU Window I have introduced two debuggers without talking about how you can employ them, and also which parts you should pay attention to. Regarding using debuggers, I refer you to their instructions in help documents. However, I want to explain briefly the important parts of a debugger; of course, I am talking about low-level debuggers, or in other words, machine-language debuggers of the x86 CPU families. All of low-level debuggers consist of the following subdivisions: o d t s z a p c You can compare Figures 1 and 2 to distinguish the difference between SoftICE and OllyDbg. When you want to trace a PE file, you should mostly consider these five subdivisions. Furthermore, every debugger comprises of some other useful parts; you should discover them by yourself. You can consider OllyDbg and SoftICE to be excellent disassemblers, but I also want to introduce another disassembler tool that is famous in the reverse engineering world. Proview or PVDasm is an admirable disassembler by the Reverse-Engineering-Community; it is still under development and bug fixing. You can find its disassmbler source engine and employ it to create your own disassembler. W32DASM can disassemble both 16- and 32-bit executable file formats. In addition to its disassembling ability, you can employ it to analyze import, export, and resource data directories data. All reverse-engineering experts know that IDA Pro can be used to investigate, not only x86 instructions, but that of various kinds of CPU types like AVR, PIC, and so forth. It can illustrate the assembly source of a portable executable file by using colored graphics and tables, and is very useful for any newbie in this area. Furthermore, it has the capability to trace an executable file inside the user mode level in the same way as OllyDbg. A good PE tools developer is conversant with the tools that save his time, so I recommend that you select some appropriate instruments to investigate the base information under a portable executable file. LordPE by y0da is still the first choice to retrieve PE file information with the possibility to modify them. PE iDentifier is valuable to identify the type of compilers, packers, and cryptors of PE files. As of now, it can detect more than 500 different signature types of PE files. Resource Hacker can be employed to modify resource directory information; icon, menu, version info, string table, and so on. WinHex, it is clear what you can do with this tool. Eventually, CFF Explorer by Ntoskrnl is what you want to have as a PE Utility tool in your arsenal; it supports PE32/64, PE rebuild included Common Language Infrastructure (CLI) file. In other words, the .NET file, a resource modifier, and much more facilities which can not be found in others. Just try to discover every unimaginable option by hand. You are ready to do the first step of making your project. I have provided a library to add a new section and rebuild the portable executable file. Before starting, I wnat you to get familiar with the headers of a PE file, by using OllyDbg. You should first open a PE file; that pops up a menu, View->Executable file. Again, you get a popup menu: Special->PE header. You will observe a scene similar to Figure 3. Now, come to the Main Menu View->Memory, and try to distinguish the sections inside the Memory map window.
(3.1.3 Which parts are important in a debugger interface?
EAX
ECX
EDX
EBX
ESP
EBP
ESI
EDI
EIP
010119E0 PUSH EBP010119E1 MOV EBP,ESP010119E3 PUSH -1010119E5 PUSH 01001570010119EA PUSH 01011D60010119EF MOV EAX,DWORD PTR FS:[0]010119F5 PUSH EAX010119F6 MOV DWORD PTR FS:[0],ESP010119FD ADD ESP,-6801011A00 PUSH EBX01011A01 PUSH ESI01011A02 PUSH EDI01011A03 MOV DWORD PTR SS:[EBP-18],ESP01011A06 MOV DWORD PTR SS:[EBP-4],0
0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ……………. 0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ……………. 0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ……..SciCalc. 0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ……..backgrou 0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd…………..
0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 b.| . 0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T . 0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |…….. 0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 …. ….
Command
SoftICE
OllyDbg
Run
F5
F9
Step Into
F11
F7
Step Over
F10
F8
Set Break Point
F8
F2
3.2 Disassembler
3.2.1 Proview disassembler
3.2.2 W32Dasm
3.2.3 IDA Pro
3.3 Some Useful Tools
3.3.1 LordPE
3.3.2 PEiD
3.3.3 Resource Hacker
3.3.4 WinHex
3.3.5 CFF Explorer
4 Add a New Section and Change the OEP
Figure 3
00000000000000020000000400000006000000080000000A0000000C0000000E00000010000000120000001400000016000000180000001A0000001C0000001D0000001E0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000300000003100000032000000330000003400000035000000360000003700000038000000390000003A0000003B0000003C
|
4D 5A 9000 0300 0000 0400 0000 FFFF 0000 B800 0000 0000 0000 4000 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0000000 |
ASCII "MZ" DW 0090 DW 0003 DW 0000 DW 0004 DW 0000 DW FFFF DW 0000 DW 00B8 DW 0000 DW 0000 DW 0000 DW 0040 DW 0000 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DD 000000F0 |
DOS EXE Signature DOS_PartPag = 90 (144.) DOS_PageCnt = 3 DOS_ReloCnt = 0 DOS_HdrSize = 4 DOS_MinMem = 0 DOS_MaxMem = FFFF (65535.) DOS_ReloSS = 0 DOS_ExeSP = B8 DOS_ChkSum = 0 DOS_ExeIP = 0 DOS_ReloCS = 0 DOS_TablOff = 40 DOS_Overlay = 0 Offset to PE signature |
|
Virtual_Address = Image_Base + Relative_Virtual_Address |
DWORD OEP_RVA = image_nt_headers-> OptionalHeader.AddressOfEntryPoint ;// OEP_RVA = 0x00012475DWORD OEP_VA = image_nt_headers-> OptionalHeader.ImageBase + OEP_RVA ;// OEP_VA = 0x01000000 + 0x00012475 = 0x01012475
PE Maker: Step 1
Download pemaker1.zip and test1.zip from the files at the end of this article.
DynLoader(), in loader.cpp, is reserved for the data of the new section—in other words, the Loader.
DynLoader Step 1
__stdcall void DynLoader(){_asm{//---------------------------------- DWORD_TYPE(DYN_LOADER_START_MAGIC)//---------------------------------- MOV EAX,01012475h // << Original OEP JMP EAX//---------------------------------- DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------}}
Unfortunately, this source can only be applied for the sample test file. You should complete it by saving the value of the original OEP in the new section, and use it to reach the real OEP. I have accomplished it in Step 2 (Section 5).
4.1 Retrieve and Rebuild PE file
I have made a simple class library to recover PE information and to use it in a new PE file.
CPELibrary Class Step 1
//----------------------------------------------------------------class CPELibrary{private: //----------------------------------------- PCHAR pMem; DWORD dwFileSize; //-----------------------------------------protected: //----------------------------------------- PIMAGE_DOS_HEADER image_dos_header; PCHAR pDosStub; DWORD dwDosStubSize, dwDosStubOffset; PIMAGE_NT_HEADERS image_nt_headers; PIMAGE_SECTION_HEADER image_section_header[MAX_SECTION_NUM]; PCHAR image_section[MAX_SECTION_NUM]; //-----------------------------------------protected: //------------------------------
