首页 > 代码库 > Linux工具开发---2编程实现对输入字符序列变换(编码/加密/散列)方式的智能判定

Linux工具开发---2编程实现对输入字符序列变换(编码/加密/散列)方式的智能判定

如何简单实现一个可以智能判定输入字符序列变换方式的小程序

本文由CSDN-蚍蜉撼青松 【主页:http://blog.csdn.net/howeverpf】原创,转载请注明出处!

问题描述:

        在分析网络数据包或者研究安全问题时,经常会遇到变换后的字符序列。而能否准确识别密文的变换算法,对进一步的分析工作很关键。常用的变换算法包括但不限于:Base64、URL编码、HTML编码、MD5散列、DES加密、RSA加密等。要求:

  1)在理解算法原理及密文特点的基础上,使用任意编程语言实现,当输入一段密文时,返回可能的变换算法。
  2)能准确识别5种以上变换或加密算法。


解答思路:

        选择用来识别的变换算法包括:URL编码、QP(全称Quoted-Printable)编码、Unicode编码、HTML特殊实体编码、Base64编码、MD5散列、SHA1散列。

        首先分析这七种变换算法的特点,分别提出判别依据与函数实现:

  • URL编码的特点是在百分号’%’紧跟两个十六进制数(大小写皆可),因此我们需要在输入字节流中找到’%’所处的位置,判定其后两个字符是否为十六进制值。若有符合此条件的,则可以大概判定使用了URL编码;若全都不符合,则不可能使用了URL编码。-----存在型判定

URL编码判定函数实现如下

// 判定是否存在URL编码
//参数 pszBuff,   待判定字符序列
//返回 若一切正常,返回 true
bool IsEncodedbyURL(char *pszBuff)
{
    int i,j;

    // 百分号 数量上是否正常
    if (g_nCountPC == ARRAY_MAX_SIZE)
        DbgMsgPrint("Please make the buffer size bigger for '%'.");
    else if (g_nCountPC == 0)
        return true;

    // 百分号 数量正常的话, 遍历待判定字符序列中所有的百分号【已由预处理的时候取得】
    //若每个百分号后紧跟的两个字符不都是十六进制值,则不存在URL编码
    for (i=0; i<g_nCountPC; i++)
    {
        j = g_arrnPosPC[i];
        if ( !(IsHex(pszBuff+j+1) && IsHex(pszBuff+j+2)) )
        {
            // 只要有一个百分号的字符不是十六进制值,都判定为不存在URL编码
            DbgMsgPrint("the char after % isn't a hex!");
            g_nIsEncodedbyURL = IDENTIFIY_RES_FALSE;
            return true;
        }
    }
    // 所有的百分号后面紧跟的都为2个十六进制数,才能基本肯定使用了URL编码
    g_nIsEncodedbyURL = IDENTIFIY_RES_CERTAIN;

    return true;
}

  • QP编码的特点是在等于号’=’紧跟两个十六进制数(字母必大写),因此我们需要在输入字节流中找到’=’号的位置,判定其后两个字符是否为十六进制值,并且若为’A’-‘F’的话,必须是大写字符。若全都不符合,则不可能为QP编码;若有符合条件的,还需继续判定所有的换行符”\r\n”之间的间隔长度是否全都小于76,若不符合,则也不可能是QP编码;这些条件都符合的,则有很大可能是QP编码。-----存在型判定

QP编码判定函数实现如下:

// 判定是否存在QP编码
//参数 pszBuff,   待判定字符序列
//返回 一切正常,返回 true
bool IsEncodedbyQP(char *pszBuff)
{
    int i,j;

    // 等于号 数量上是否正常
    if (g_nCountEQ == ARRAY_MAX_SIZE)
        DbgMsgPrint("Please make the buffer size bigger for '='.");
    else if (g_nCountEQ == 0)
        return true;

    // 等于号 数量正常的话, 遍历待判定字符序列中所有的等于号【已由预处理的时候取得】
    for (i=0; i<g_nCountEQ; i++)
    {
        j = g_arrnPosEQ[i];
        // 对于QP编码,等于号后面的两个字符要么是十六进制值(字母的话需大写),要么是 \r\n
        if ( RegnizeChar(pszBuff+j+1)<=0 || RegnizeChar(pszBuff+j+2)<=0)
        {
            if( *(pszBuff+j+1)!='\r' || *(pszBuff+j+2)!='\n' )
            {
                // 只要有一个等于号后面的字符不符合,就不是QP编码
                g_nIsEncodedbyQP = IDENTIFIY_RES_FALSE;
                return true;
            }
        }
    }
    // 所有的等于号后面紧跟的字符都符合,才能说可能使用了QP编码
    g_nIsEncodedbyQP = IDENTIFIY_RES_MAYBE;

    for (i=0; i<g_nconutcr-1 i="" qp="" r="" n="" 76="" if="" g_arrnposcr="" 1="" -=""> LINE_MAX_LENGTH+1)
            return true;
    }
    // 行长度都小于限定值,则能基本肯定使用了QP编码
    g_nIsEncodedbyQP = IDENTIFIY_RES_CERTAIN;

    return true;
}

  • Unicode编码的特点是”\u”后紧跟四个十六进制数(大小写皆可),因此我们需要在输入字节流中找到反斜线’\’的位置,判定其后紧跟的字符是否为’u’,若是再后面跟的四个字符是十六进制数,则可以确定使用了Unicode编码;反之所找不到这样的模式串,则不可能使用了Unicode编码。-----存在型判定

Unicode编码判定函数实现如下

// 判定是否存在Unicode编码
//参数 pszBuff,   待判定字符序列
//返回 一切正常,返回 true
bool IsEncodedbyUnicode(char *pszBuff)
{
    int i,j;

    // 反斜杆 数量上是否正常
    if (g_nCountBS == ARRAY_MAX_SIZE)
        DbgMsgPrint("Please make the buffer size bigger for '\'.");
    else if (g_nCountBS == 0)
        return true;

    // 反斜杆 数量正常的话, 遍历待判定字符序列中所有的反斜杆【已由预处理的时候取得】
    for (i=0; i<g_nCountBS; i++)
    {
        j = g_arrnPosBS[i];
        if (*(pszBuff+j+1)=='u') // 反斜杆后面紧跟的字符是否为’u’
        {
            // ”\u”后紧跟的四个字符是否为十六进制数
            if ( IsHex(pszBuff+j+2) && IsHex(pszBuff+j+3) && IsHex(pszBuff+j+4) && IsHex(pszBuff+j+5) )
            {
                // 只要有一个符合条件的,就可以认为一定存在Unicode编码
                g_nIsEncodedbyUnicode = IDENTIFIY_RES_CERTAIN;
                return true;
            }
        }
    }
    // 所有的反斜杆后面的字符都不符合条件,才确认不存在Unicode编码
    g_nIsEncodedbyUnicode = IDENTIFIY_RES_FALSE;

    return true;
}

  • HTML特殊实体编码的特点是在取地址符’&’和分号’;’之间放实体名或实体编号。实体命名使用26个英文字母(大小写皆可),实体编号是以’#’开始的十进制数。所以我们判定时,需要找到所有’&’和’;’的位置,判定每个’&’与离它最近的’;’之间的字符串,是否符合实体命名或编号的规范。若有符合这些要求的,则可以大概判定使用了HTML编码,反之,肯定没使用HTML特殊实体编码。-----存在型判定

HTML特殊实体编码判定函数实现如下

// 判定是否存在HTML特殊字符编码
//参数 pszBuff,   待判定字符序列
//返回 一切正常,返回 true
bool IsEncodedbyHtml(char *pszBuff)
{
    int i,j,nTemp;
    bool bFindSC;

    // 取址符与分号 数量上是否正常
    if (g_nCountAMP == ARRAY_MAX_SIZE)
        DbgMsgPrint("Please make the buffer size bigger for '&'.");
    if (g_nCountSC == ARRAY_MAX_SIZE)
        DbgMsgPrint("Please make the buffer size bigger for ';'.");

    if (g_nCountAMP==0 || g_nCountSC==0)
        return true;

    nTemp = 0;
    for (i=0; i<g_nCountAMP; i++)
    {
        bFindSC = false;
        for (j=nTemp; j<g_nCountSC; j++)
        {
            if ( g_arrnPosSC[j]>g_arrnPosAMP[i] )
            {
                bFindSC = true;
                break;
            }
        }
        if (!bFindSC)
            continue;

        nTemp = j;
        if (*(pszBuff+g_arrnPosAMP[i]+1) == '#')
        {
            for (j=g_arrnPosAMP[i]+2; j<g_arrnPosSC[nTemp]; j++)
            {
                if (RegnizeChar(pszBuff+j) != 2)
                {
                    g_nIsEncodedbyHtml = IDENTIFIY_RES_FALSE;
                    return true;
                }
            }
        }
        else
        {
            for (j=g_arrnPosAMP[i]+1; j<g_arrnPosSC[nTemp]; j++)
            {
                if ( *(pszBuff+j)>='A' && *(pszBuff+j)<='Z')
                    continue;
                else if ( *(pszBuff+j)>='a' && *(pszBuff+j)<='z')
                    continue;

                g_nIsEncodedbyHtml = IDENTIFIY_RES_FALSE;
                return true;
            }
        }

        g_nIsEncodedbyHtml = IDENTIFIY_RES_CERTAIN;
        break;
    }
    return true;
}

  • Base64编码的特点是编码后的结果只可能出现64个特定字符、换行符、等于号,并且长度必为4的倍数。因此,我们判定的时候首先检查有没有超出范围的非法字符;如果没有,接着检查等于号是否只出现在最后,并且数量不大于2;如果符合,继续检查输入总长度减去换行符长度后得到的值是否为4的倍数。这些条件只要有一个不符合,都不可能是Base64编码,反之则有可能是Base64编码。-----是非型判定
  • MD5散列输出的长度一般是128bits,一般使用32个十六进制数表示。因此,我们判定的时候首先检查输入里面是否存在非16进制数的非法字符,再检查长度是否为32,都符合,则可能是MD5散列,反之,一定不是MD5散列。-----是非型判定
  • SHA1散列输出的长度一般是160bits,一般使用40个十六进制数表示。因此,我们判定的时候首先检查输入里面是否存在非16进制数的非法字符,再检查长度是否为40,都符合,则可能是SHA1散列,反之,一定不是SHA1散列。-----是非型判定

Base64编码判定【兼带判定是否为 MD5/SHA1 散列】的函数实现如下

// 判定是否为Base64编码
// 顺带判定是否为 MD5/SHA1 散列
//参数 pszBuff,   待判定字符序列
//返回 一切正常,返回 true
bool IsEncodedbyBase64(void)
{
    int nRealLength,i;

    // 先检查预处理的时候有没有遇到非法字符【对于Base64编码】
    if ( g_nIsEncodedbyBase64 == IDENTIFIY_RES_FALSE )
    {
        return true;
    }
    else if (g_nCountEQ > 2)
    {
        g_nIsEncodedbyBase64 = IDENTIFIY_RES_FALSE;
        return true;
    }

    // 当数据源为文件,且完整的数据都已被读进来来时,检查长度是否为4的倍数
    if ( (g_pszEncodedFilePath != NULL) && (g_nEncodedCotentLength >= BUFFER_MAX_SIZE) )
    {
        DbgMsgPrint("The buffer is too small for the whole file, can't regnize the Base64/MD5/SHA1!");
        return true;
    }
    nRealLength = g_nEncodedCotentLength - g_nConutCR - g_nCountLF; // 获取字符序列的实际长度(除去回车、换行)
    if ( nRealLength%4 != 0 )
    {
        // 基于Base64、MD5、SHA1的输出字符序列的特点,真实长度不为4的倍数的话,不可能是Base64/MD5/SHA1
        g_nIsEncodedbyBase64 = IDENTIFIY_RES_FALSE;
        g_nIsEncodedbyMD5   = IDENTIFIY_RES_FALSE;
        g_nIsEncodedbySHA1  = IDENTIFIY_RES_FALSE;

        return true;
    }

    // 经Base64编码的字符序列,其最后一个或最后两个字符可能是等号; 而MD5、SHA1的输出字符序列中不含等号
    if ( g_nCountEQ > 0)
    {
        for (i=0; i<g_nCountEQ; i++)
        {
            // 等号是否在最后一个或两个
            if (g_arrnPosEQ[i] < g_nEncodedCotentLength-2)
            {
                g_nIsEncodedbyBase64 = IDENTIFIY_RES_FALSE;
                return true;
            }
        }
        g_nIsEncodedbyBase64 = IDENTIFIY_RES_MAYBE;
    }
    else
    {
        g_nIsEncodedbyBase64 = IDENTIFIY_RES_MAYBE;

        // MD5散列输出的长度一般是128bits,一般使用32个十六进制数表示
        // SHA1散列输出的长度一般是160bits,一般使用40个十六进制数表示
        // 可通过长度对二者进行简单的区分
        if (nRealLength == 32)
        {
            g_nIsEncodedbyMD5   = IDENTIFIY_RES_MAYBE;
            g_nIsEncodedbySHA1  = IDENTIFIY_RES_FALSE;
            return true;
        }
        else if (nRealLength == 40)
        {
            g_nIsEncodedbySHA1  = IDENTIFIY_RES_MAYBE;
            g_nIsEncodedbyMD5   = IDENTIFIY_RES_FALSE;
            return true;
        }
    }

    return true;
}

        前面提到的七种变换算法的识别方法中,提到了两个名词,存在型判定是非型判定。对于存在型判定,我们判定的是输入中是否存在某种变换算法;而对于是非型判定,我们判定的是整个输入是否整体使用了某种变换算法。由于这种区别,我们在这实现是非型判定的时候,就要求输入必须是完整的。(我在程序中用读入的长度是否小于输入缓存size来简单地判定)。

        在前文提到的七种变换算法的识别方法中,很多都需要对一些特殊字符进行定位,例如:百分号’%’(URL编码),等于号’=’(QP编码、Base64编码),反斜线’\’(Unicode编码),等等。而这些特殊字符在原始输入字符序列中的位置和出现次数,都由一个预处理函数完成【前文的几个判定函数实现中,也有提到】,其实现如下:

// 对待判定字符序列的预处理
//参数 pszBuff,   待判定字符序列
//参数 nBuffSize, 待判定字符序列的长度
//返回 若一切正常,返回 true
bool PreProcess(char *pszBuff, int nBuffSize)
{
    int i;

    for (i=0; i<nBuffSize; i++)
    {
        if (IsHex(pszBuff+i))
            continue;
        else
        {
            // 出现非十六进制值,则必然不可能是 MD5/SHA1 散列编码
            g_nIsEncodedbyMD5  = IDENTIFIY_RES_FALSE;
            g_nIsEncodedbySHA1 = IDENTIFIY_RES_FALSE;
        }

        if ((*(pszBuff+i)>='G' && *(pszBuff+i)<='Z') ||
            (*(pszBuff+i)>='g' && *(pszBuff+i)<='z') ||
            *(pszBuff+i)=='+' || *(pszBuff+i)=='-')
        {
            continue;
        }
        else if (*(pszBuff+i)=='\r')
        {
            if (g_nConutCR < ARRAY_MAX_SIZE)
                g_arrnPosCR[g_nConutCR++] = i;  // 记录回车符 \r 出现的位置与次数
            continue;
        }
        else if (*(pszBuff+i)=='\n')
        {
            if (g_nCountLF < ARRAY_MAX_SIZE)
                g_arrnPosLF[g_nCountLF++] = i;  // 记录换行符 \n 出现的位置与次数
            continue;
        }
        else if (*(pszBuff+i)=='=')
        {
            if (g_nCountEQ < ARRAY_MAX_SIZE)
                g_arrnPosEQ[g_nCountEQ++] = i;  // 记录等于号 = 出现的位置与次数
        }
        else
        {
            // 超出了 BASE64 编码结果集的范围
            g_nIsEncodedbyBase64 = IDENTIFIY_RES_FALSE;
        }

        if (*(pszBuff+i)=='\\')
        {
            if (g_nCountBS < ARRAY_MAX_SIZE)
                g_arrnPosBS[g_nCountBS++] = i;  // 记录反斜杆 \\ 出现的位置与次数
        }
        else if (*(pszBuff+i)=='%')
        {
            if (g_nCountPC < ARRAY_MAX_SIZE)
                g_arrnPosPC[g_nCountPC++] = i;  // 记录百分号 % 出现的位置与次数
        }
        else if (*(pszBuff+i)=='&')
        {
            if (g_nCountAMP < ARRAY_MAX_SIZE)
                g_arrnPosAMP[g_nCountAMP++] = i;  // 记录取址符 & 出现的位置与次数
        }
        else if (*(pszBuff+i)==';')
        {
            if (g_nCountSC < ARRAY_MAX_SIZE)
                g_arrnPosSC[g_nCountSC++] = i;  // 记录分号 ; 出现的位置与次数
        }
    }

    return true;
}


工具实现:

 main.cpp 主程序文件内容       

#include "base.h"

char *g_pszExecPath = NULL;
int g_nWorkMode = 0;
char *g_pszEncodedFilePath = NULL;
char *g_pszEncodedCotent   = NULL;
int g_nEncodedCotentLength = 0;
int g_arrnPosCR[ARRAY_MAX_SIZE]; //回车符 \r 0D 13 位置记录
int g_arrnPosLF[ARRAY_MAX_SIZE]; //换行符 \n 0A 10 位置记录
int g_arrnPosBS[ARRAY_MAX_SIZE]; //反斜线 \\ 5C 92 位置记录
int g_arrnPosEQ[ARRAY_MAX_SIZE]; //等于号  = 3D 61 位置记录
int g_arrnPosPC[ARRAY_MAX_SIZE]; //百分号  % 25 37 位置记录
int g_arrnPosAMP[ARRAY_MAX_SIZE];//取地址符& 26 38 位置记录
int g_arrnPosSC[ARRAY_MAX_SIZE]; //分号    ; 3b 59 位置记录
int g_nConutCR = 0;
int g_nCountLF = 0;
int g_nCountBS = 0;
int g_nCountEQ = 0;
int g_nCountPC = 0;
int g_nCountAMP= 0;
int g_nCountSC = 0;
// 识别结果
int g_nIsEncodedbyURL     = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbyQP      = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbyUnicode = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbyHtml    = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbyBase64  = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbyMD5     = IDENTIFIY_RES_UNKNOW;
int g_nIsEncodedbySHA1    = IDENTIFIY_RES_UNKNOW;
// 函数声明
bool GetParam(char* argv[]);
bool GetExecPath(void);
int RegnizeChar(char*);
bool IsHex(char*);
bool PreProcess(char*, int);
bool IsEncodedbyURL(char*);
bool IsEncodedbyQP(char*);
bool IsEncodedbyUnicode(char*);
bool IsEncodedbyHtml(char*);
bool IsEncodedbyBase64(void);
bool FreeGloabl(char*);


int main(int argc, char* argv[])
{
    int nFileHandle;
    char szReadTemp[BUFFER_MAX_SIZE];
    size_t nReadSize;
    const char *pszPrintInfo[4];
    pszPrintInfo[0] = "IDENTIFIY_RES_FALSE";
    pszPrintInfo[1] = "IDENTIFIY_RES_UNKNOW";
    pszPrintInfo[2] = "IDENTIFIY_RES_MAYBE";
    pszPrintInfo[3] = "IDENTIFIY_RES_CERTAIN";

    // 参数个数合法性判定
    if (argc != 3)
    {
        DbgErrPrint("Invalid count of parameter! \nUse this commnd like:\n             \tIdentify -s [encoded content]\n             or\n             \tIdentify -f [filename]");
        return -1;
    }

    // 获取参数值
    if (!GetParam(argv))
    {
        DbgErrPrint("Invalid value of parameter! \nUse this commnd like:\n             \tIdentify -s [encoded content]\n             or\n             \tIdentify -f [filename]");
        return -1;
    }

    // 若待判定的是一个文件,则需将文件内容读出
    if (g_nWorkMode == IDENTIFIY_SRC_FILE)
    {
        nFileHandle = open (g_pszEncodedFilePath, O_RDONLY);
        if (nFileHandle == -1)
        {
            DbgSysErrPrint("Open encoded file failed!");
            return -1;
        }

        nReadSize = read(nFileHandle, szReadTemp, BUFFER_MAX_SIZE);
        close(nFileHandle);
        switch(nReadSize)
        {
        case -1:
            DbgSysErrPrint("Read from encoded file failed!");
            return -1;
        case 0:
            DbgErrPrint("Empty encoded file!");
            return -1;
        default:
            g_pszEncodedCotent = szReadTemp;
            g_nEncodedCotentLength = nReadSize;
        }
    }

    // 预处理
    if (!PreProcess(g_pszEncodedCotent, g_nEncodedCotentLength))
    {
        DbgErrPrint("PreProcess failed!");
        return -1;
    }

    // 依次判定各种编码的可能性
    IsEncodedbyURL(g_pszEncodedCotent);
    IsEncodedbyUnicode(g_pszEncodedCotent);
    IsEncodedbyQP(g_pszEncodedCotent);
    IsEncodedbyHtml(g_pszEncodedCotent);
    IsEncodedbyBase64();

    // 打印结果
    DbgMsgPrint("URL/URI          encode identification result: %s", pszPrintInfo[g_nIsEncodedbyURL+1]);
    DbgMsgPrint("Quoted-Printable encode identification result: %s", pszPrintInfo[g_nIsEncodedbyQP+1]);
    DbgMsgPrint("Unicode          encode identification result: %s", pszPrintInfo[g_nIsEncodedbyUnicode+1]);
    DbgMsgPrint("Html special     encode identification result: %s", pszPrintInfo[g_nIsEncodedbyHtml+1]);
    DbgMsgPrint("Base64           encode identification result: %s", pszPrintInfo[g_nIsEncodedbyBase64+1]);
    DbgMsgPrint("MD5 hash         encode identification result: %s", pszPrintInfo[g_nIsEncodedbyMD5+1]);
    DbgMsgPrint("SHA1 hash        encode identification result: %s", pszPrintInfo[g_nIsEncodedbySHA1+1]);

    FreeGloabl(argv[2]);

    return 0;
}

// 获取程序的启动参数
//参数 argv, 程序启动参数列表
bool GetParam(char* argv[])
{
    if (strncmp(argv[1], "-s", 2)==0)  // 要判定的字符序列直接通过参数传进来
    {
        g_nWorkMode = IDENTIFIY_SRC_STRING;
        g_pszEncodedCotent = argv[2];
        g_nEncodedCotentLength = strlen(g_pszEncodedCotent);
        DbgMsgPrint("Identify string: %s", g_pszEncodedCotent);
        return true;
    }
    else if (strncmp(argv[1], "-f", 2)==0)  //要判定的是一个文件
    {
        g_nWorkMode = IDENTIFIY_SRC_FILE;
        if (argv[2][0] == '/')
        {
            g_pszEncodedFilePath = argv[2];
        }
        else
        {
            if (!GetExecPath())
            {
                DbgErrPrint("Get the path of Identify failed!");
                return false;
            }
            g_pszEncodedFilePath = new char[strlen(g_pszExecPath)+strlen(argv[2])+1];
            ASSERT(g_pszEncodedFilePath!=NULL);
            strcpy(g_pszEncodedFilePath, g_pszExecPath);
            strcat(g_pszEncodedFilePath, argv[2]);
        }
        DbgMsgPrint("Identify file: %s", g_pszEncodedFilePath);
        return true;
    }

    return false;
}

// 获取可执行文件所在的目录路径
//返回 成功返回true
bool GetExecPath(void)
{
    char szExecPath[512];
	int nCount;
	int i;

	//先获取可执行文件的路径
	nCount = readlink("/proc/self/exe", szExecPath, sizeof(szExecPath));
	if (nCount == -1)
	{
		DbgErrPrint("Readlink failed!");
		return false;
	}

	//提取可执行文件所在的目录路径
	szExecPath[nCount] = '\0';  // 字符数组转换成C字符串
	for (i=nCount-1; i>0; i--)
	{
		if (szExecPath[i-1] == '/')
			break;
	}
	if (i == 0)  //不存在目录分隔符
	{
		DbgErrPrint("Get exec path failed!");
		return false;
	}
	szExecPath[i] ='\0';

	g_pszExecPath = new char[i+1];
	ASSERT(g_pszExecPath != NULL);
	strcpy(g_pszExecPath, szExecPath);

    return true;
}

// 识别输入字符的类型
//参数 pszValue, 指向待识别的字符
//返回 若为数字,返回 2;  若为大写英文字符,返回 1; 若为小写英文字符,返回 0; 若都不是,返回 -1.
int RegnizeChar(char *pszValue)
{
    if (*pszValue>='0' && *pszValue<='9')
        return 2;
    else if (*pszValue>='A' && *pszValue<='F')
        return 1;
    else if (*pszValue>='a' && *pszValue<='f')
        return 0;
    else
        return -1;
}

// 判定输入字符是否可能是十六进制值
//参数 pszValue, 指向待识别的字符
//返回 若识别为非16进制值,返回 false; 反之,返回 true.
bool IsHex(char *pszValue)
{
    if (RegnizeChar(pszValue)<0)
        return false;

    return true;
}

/*此处略去预处理函数与几个判定函数的定义,参看前文 */

// 释放全局变量
//参数 pszParam【输入】,最后一个启动参数
//返回 成功返回true
bool FreeGloabl(char *pszParam)
{
    if (g_pszExecPath != NULL)
    {
        delete [] g_pszExecPath;
        g_pszExecPath = NULL;
    }

    // 仅当启动参数为相对路径时,才需要释放
    if (g_pszEncodedFilePath != NULL && g_pszEncodedFilePath != pszParam)
    {
        delete [] g_pszEncodedFilePath;
        g_pszEncodedFilePath = NULL;
    }

    return true;
}

base.h 头文件内容:

#ifndef ENCODEIDENTIFIY_BASE_H
#define ENCODEIDENTIFIY_BASE_H

#include <stdio.h>          //ANSI标准 输入输出
#include <stdlib.h>         //ANSI标准 常用函数库
#include <time.h>           //ANSI标准 日期与时间处理
#include <signal.h>         //ANSI标准 信号处理
#include <errno.h>          //ANSI标准 错误码定义
#include <assert.h>         //ANSI标准 验证程序断言
#include <unistd.h>         //POSIX 符号常量( 系统常用API的封装 )
#include <strings.h>        //POSIX 字符串处理( 基本类似标准的string.h )
#include <fcntl.h>          //POSIX 文件操作
#include <sys/stat.h>       //POSIX 文件属性
#include <sys/types.h>      //POSIX 基本系统数据类型

#include <string>

using namespace std;

// 定义是否使用调试模式
#define DEBUG
// 定义调试宏
#ifdef DEBUG
	#define ASSERT(_x_)         assert(_x_)
	#define DbgSysErrPrint(_x_) perror(_x_)
	#define DbgMsgPrint(format,...) printf(format"\n", ##__VA_ARGS__)
	#define DbgErrPrint(format,...) printf("File: "__FILE__", Line: %05d, Func: %s ---> "format"\n", __LINE__, __FUNCTION__, ##__VA_ARGS__)
#else
	#define ASSERT(_x_)
	#define DbgSysErrPrint(_x_)
	#define DbgMsgPrint(format,...)
	#define DbgErrPrint(format,...)
#endif

#define ARRAY_MAX_SIZE  512
#define BUFFER_MAX_SIZE 2048
#define LINE_MAX_LENGTH 76

// 定义识别来源
#define IDENTIFIY_SRC_STRING  1   // 识别字符串
#define IDENTIFIY_SRC_FILE    2   // 识别文件
// 定义识别结果
#define IDENTIFIY_RES_CERTAIN 2   // 确认是某种编码
#define IDENTIFIY_RES_MAYBE   1   // 可能是某种编码
#define IDENTIFIY_RES_UNKNOW  0   // 无法确认
#define IDENTIFIY_RES_FALSE  -1   // 确认不是某种编码

// 可供外部文件调用的全局变量声明
extern char *g_pszExecPath;
extern int g_nWorkMode;
extern char *g_pszEncodedFilePath;
extern char *g_pszEncodedCotent;
extern int g_nEncodedCotentLength;

#endif // ENCODEIDENTIFIY_BASE_H