菜单

Base64编码解码剪贴板文本,UPX源码分析

2019年8月2日 - 4166am金沙下载
Base64编码解码剪贴板文本,UPX源码分析

可用于在有限的网络权限下加密传输文本。

256位密钥加密传输文本。

0x00
前言

encodeDESstr.cpp

encodeAESstr.cpp

UPX作为一个跨平台的著名开源压缩壳,随着Android的兴起,许多开发者和公司将其和其变种应用在.so库的加密防护中。虽然针对UPX及其变种的使用和脱壳都有教程可查,但是至少在中文网络里并没有针对其源码的分析。作为一个好奇宝宝,我花了点时间读了一下UPX的源码并梳理了其对ELF文件的处理流程,希望起到抛砖引玉的作用,为感兴趣的研究者和使用者做出一点微不足道的贡献。

// encodeDESstr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "encodeDESstr.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std; 
//编码表
const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char Tmp1,Tmp2,Tmp3;
string strEncode;
int LineLength=0;

void set1st(unsigned char c)
{
    Tmp1 = c;
}

void set2nd(unsigned char c)
{
    Tmp2 = c;
}

void set3rd(unsigned char c)
{
    Tmp3 = c;
    strEncode+= EncodeTable[Tmp1 >> 2];
    strEncode+= EncodeTable[((Tmp1 << 4) | (Tmp2 >> 4)) & 0x3F];
    strEncode+= EncodeTable[((Tmp2 << 2) | (Tmp3 >> 6)) & 0x3F];
    strEncode+= EncodeTable[Tmp3 & 0x3F];
    if(LineLength+=4,LineLength==76) 
    {
        strEncode+="\r\n";
        LineLength=0;
    }
}

void (*base64_func[])(unsigned char c)={
    set1st,set2nd,set3rd
};

long n=0;
long counter=0;
char srcBytes[8] = {0};
char szLast8Bits[8] = {0};
char szSubKeys[16][48];//储存16组48位密钥
char szCiphertextRaw[64]; //储存二进制密文(64个Bits) int 0,1
char szCiphertextInBytes[8];//储存8位密文
char szPlaintextInBytes[8];//储存8位明文字符串
char szPlaintext[9];//储存8位明文字符串,最后一位存'\0'

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

void DES_Bytes2Bits(char *srcBytes, char* dstBits, unsigned int sizeBits)
{
    unsigned int i=0;
    for(i=0; i < sizeBits; i++)
        dstBits[i] = ((srcBytes[i>>3]<<(i&7)) & 128)>>7;
}

void DES_CreateSubKey(char* sz_56key)
{
    char szTmpL[28] = {0};
    char szTmpR[28] = {0};
    char szCi[28] = {0};
    char szDi[28] = {0};
    char szTmp56[56] = {0};
    int i=0,j=0;

    memcpy(szTmpL,sz_56key,28);
    memcpy(szTmpR,sz_56key + 28,28);

    for(i=0;i<16;i++)
    {
        //shift to left
        //Left 28 bits
        memcpy(szCi,szTmpL + Shift_Table[i],28 - Shift_Table[i]);
        memcpy(szCi + 28 - Shift_Table[i],szTmpL,Shift_Table[i]);
        //Right 28 bits
        memcpy(szDi,szTmpR + Shift_Table[i],28 - Shift_Table[i]);
        memcpy(szDi + 28 - Shift_Table[i],szTmpR,Shift_Table[i]);

        //permuted choice 48 bits key
        memcpy(szTmp56,szCi,28);
        memcpy(szTmp56 + 28,szDi,28);
        for(j=0;j<48;j++)
            szSubKeys[i][j] = szTmp56[PC2_Table[j]-1];
        //Evaluate new szTmpL and szTmpR
        memcpy(szTmpL,szCi,28);
        memcpy(szTmpR,szDi,28);
    }
}

void DES_InitializeKey(char* srcBytes)
{
    //convert 8 char-bytes key to 64 binary-bits
    char sz_64key[64] = {0};
    char sz_56key[56] = {0};
    int k=0;
    DES_Bytes2Bits(srcBytes,sz_64key,64);
    //PC 1
    for(k=0;k<56;k++)
        sz_56key[k] = sz_64key[PC1_Table[k]-1];
    DES_CreateSubKey(sz_56key);
}

void DES_InitialPermuteData(char* _src,char* _dst)
{
    //IP
    int i=0;
    for(i=0;i<64;i++)
        _dst[i] = _src[IP_Table[i]-1];
}

void DES_ExpansionR(char* _src,char* _dst)
{
    int i=0;
    for(i=0;i<48;i++)
        _dst[i] = _src[E_Table[i]-1];
}

void DES_XOR(char* szParam1,char* szParam2, unsigned int uiParamLength, char* szReturnValueBuffer)
{
    unsigned int i=0;
    for(i=0; i<uiParamLength; i++)
        szReturnValueBuffer[i] = szParam1[i] ^ szParam2[i];
}

void DES_Int2Bits(unsigned int _src, char* dstBits)
{
    unsigned int i=0;
    for(i=0; i < 4; i++)
        dstBits[i] = ((_src<<i) & 8)>>3;
}

void DES_CompressFuncS(char* _src48, char* _dst32)
{
    char bTemp[8][6]={0};
    char dstBits[4]={0};
    int i=0,iX=0,iY=0,j=0;

    for(i=0;i<8;i++)
    {
        memcpy(bTemp[i],_src48+i*6,6);
        iX = (bTemp[i][0])*2 + (bTemp[i][5]);
        iY = 0;
        for(j=1;j<5;j++)
            iY += bTemp[i][j]<<(4-j);
        DES_Int2Bits(S_Box[i][iX][iY], dstBits);
        memcpy(_dst32 + i * 4, dstBits, 4);
    }
}

void DES_PermutationP(char* _src,char* _dst)
{
    int i=0;
    for(i=0;i<32;i++)
        _dst[i] = _src[P_Table[i]-1];
}

void DES_FunctionF(char* sz_Li,char* sz_Ri,unsigned int iKey)
{
    char sz_48R[48] = {0};
    char sz_xor48[48] = {0};
    char sz_P32[32] = {0};
    char sz_Rii[32] = {0};
    char sz_Key[48] = {0};
    char s_Compress32[32] = {0};
    memcpy(sz_Key,szSubKeys[iKey],48);
    DES_ExpansionR(sz_Ri,sz_48R);
    DES_XOR(sz_48R,sz_Key,48,sz_xor48);
    DES_CompressFuncS(sz_xor48,s_Compress32);
    DES_PermutationP(s_Compress32,sz_P32);
    DES_XOR(sz_P32,sz_Li,32,sz_Rii);
    memcpy(sz_Li,sz_Ri,32);
    memcpy(sz_Ri,sz_Rii,32);
}

void DES_Bits2Bytes(char *dstBytes, char* srcBits, unsigned int sizeBits)
{
    unsigned int i=0;
    memset(dstBytes,0,sizeBits>>3);
    for(i=0; i < sizeBits; i++)
        dstBytes[i>>3] |= (srcBits[i] << (7 - (i & 7)));
}

void DES_EncryptData(char* _srcBytes)
{
    char szSrcBits[64] = {0};
    char sz_IP[64] = {0};
    char sz_Li[32] = {0};
    char sz_Ri[32] = {0};
    char sz_Final64[64] = {0};
    int i=0,j=0;

    DES_Bytes2Bits(_srcBytes,szSrcBits,64);
    //IP
    DES_InitialPermuteData(szSrcBits,sz_IP);
    memcpy(sz_Li,sz_IP,32);
    memcpy(sz_Ri,sz_IP + 32,32);

    for(i=0;i<16;i++)
        DES_FunctionF(sz_Li,sz_Ri,i);
    //so D=LR

    memcpy(sz_Final64,sz_Ri,32);
    memcpy(sz_Final64 + 32,sz_Li,32);

    //~IP
    for(j=0;j<64;j++)
        szCiphertextRaw[j] = sz_Final64[IPR_Table[j]-1];
    DES_Bits2Bytes(szCiphertextInBytes,szCiphertextRaw,64);
}

void des_deal(int idx,char c)
{
    srcBytes[7]=c;
    memcpy(szLast8Bits,srcBytes,8); //+ ((counter%64/8-1)<<3)
    DES_EncryptData(szLast8Bits);
    for(int i=0;i<8;i++)
        base64_func[(n++)%3](szCiphertextInBytes[i]);
}

void des_store(int idx,char c)
{
    srcBytes[idx]=c;
}

void (*des_func[])(int idx,char c)={
    des_store,des_deal
};

void des_adpter(char c)
{
    int idx=(counter++)%8;
    des_func[counter%8==0](idx,c);
}

BYTE m_MaxBits = 9;
int m_TotalBits = 0;
DWORD m_SavedData = 0;
struct dicElement
{
    DWORD   m_Prefix;       //  keep the prefix of the element
    BYTE    m_Letter;       //  keep the letter of the element

    dicElement()
    {
        m_Prefix = 0;
        m_Letter = 0;
    }
};
void GetBytesFromCode(CPtrArray *m_dictionary,CByteArray *Buffer, DWORD code)
{
    //  Fill an array with bytes using the code for retrieving 
    //  those bytes from the dictionary elements

    //  Since we dont have 0-255 in the dictionary we have to make 
    //  sure, that if we get below 256 we stop (but still add that code)
    //  Every code higher then 255, will have a letter attached to it,
    //  which we use for getting the string back.

    while (code > 255)
    {
        dicElement *tmpEl = (dicElement*)m_dictionary->GetAt(code - 256);
        Buffer->Add(tmpEl->m_Letter);
        code = tmpEl->m_Prefix;
    }
    Buffer->Add((BYTE)code);
}

void CompressData(DWORD toSave)
{
    //  Move the data you want to write few bits to the left
    //  and combine it with the already existing data in the buffer
    m_SavedData |= toSave << (32 - m_MaxBits - m_TotalBits);
    //  Add the new added number of bits to the total bits counter
    m_TotalBits += m_MaxBits;
    //  Check if it's possible to enter the data to the file
    //  (over and equal a byte of data)
    while (m_TotalBits >= 8)
    {
        //  Get the byte we want to write
        DWORD writeData = m_SavedData;
        writeData >>= 24;
        des_adpter(writeData);
        //  remove the byte from the buffer
        m_SavedData <<= 8;
        //  Remove the byte from the counter
        m_TotalBits -= 8;
    }
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        cerr << _T("Fatal Error: MFC initialization failed") << endl;
        nRetCode = 1;
    }
    else
    {
        if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) //CF_UNICODETEXT
        {
            HGLOBAL hMem = GetClipboardData(CF_TEXT); 
            if (hMem != NULL) 
            {
                LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 
                if (lpStr != NULL)
                    GlobalUnlock(hMem);
                DES_InitializeKey("dsdfgsff");
                DWORD m_MaxCode[32]={0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF,0x1FFFF,0x3FFFF,0x7FFFF,0xFFFFF,0x1FFFFF,0x3FFFFF,0x7FFFFF,0xFFFFFF,0x1FFFFFF,0x3FFFFFF,0x7FFFFFF,0xFFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF};
                CPtrArray *m_dictionary= new CPtrArray;
                long result = 0;
                BYTE readByte = 0;
                DWORD resAdd = 256;
                //  Get the total file size
                DWORD prefix=*lpStr++;
                //  Go over the rest of the file and read it
                while (readByte=*lpStr++)
                {
                    //  Check if the prefix and readByte combination exist in the dictionary
                    //  Returns the code of an element from the dictionary
                    //  by searching for the prefix and letter assosiated with
                    //  that element code.
                    //  Returns -1 if no entry was found
                    int total = m_dictionary->GetSize();
                    dicElement *temp = NULL;
                    for (int counter = 0; counter < total; counter++)
                    {
                        temp = (dicElement*)m_dictionary->GetAt(counter);
                        if ((temp->m_Prefix == prefix) && 
                            (temp->m_Letter == readByte))
                            break;
                        temp = NULL;
                    }
                    if (temp != NULL)
                        result =counter + 256;
                    else
                        result =-1;
                    //  If not exist
                    if (result == -1)
                    {
                        //  Add the new combination
                        //  Add a dictionary element.
                        //  Since the dictionary should already have all the values
                        //  between 0-255, we start it from 256.
                        dicElement *temp = new dicElement;
                        temp->m_Prefix = prefix;
                        temp->m_Letter = readByte;
                        m_dictionary->Add(temp);
                        resAdd = m_dictionary->GetSize() + 255;
                        //  Calculate the new bit size needed to encode the file
                        //  Check the value of the parameter against the Maximum number possible
                        //  and then returns the counter
                        //  This can also be acheived by right shifting the value until we get 0
                        //  and counting the number of times we doing it.
                        for (BYTE counter = 0; counter < 32; counter++)
                            if (resAdd <= m_MaxCode[counter])
                                break;
                        m_MaxBits = counter;
                        //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
                        //  then the minimal number of bits is check to return a 9 in case a lower value will be
                        //  reached in the application
                        if (m_MaxBits < 9)
                            m_MaxBits = 9;  
                        //  Send the prefix for compression in to the destination file
                        CompressData(prefix);
                        //  Set the prefix as the readByte
                        prefix = readByte;
                        //  Initiate the result
                        result = -1;
                        delete temp;
                    }
                    else
                    {
                        //  Set the prefix as the result
                        prefix = result;
                        readByte = 0;
                    }
                }
                //  Insert to the file the maximum number of bit (for signaling the end of the
                //  compression\decompression)
                CompressData(prefix);
                CompressData(m_MaxCode[m_MaxBits]);
                //  Flash the rest of the file with 0
                CompressData(0);
                int iParts=0,iResidue=0,i=0;
                char szLast8Bits[8] = {0};
                if(counter<8)
                {
                    char _temp8bytes[8] = {0};
                    memcpy(_temp8bytes,srcBytes,counter);
                    DES_EncryptData(_temp8bytes);
                    for(int i=0;i<8;i++)
                        base64_func[(n++)%3](szCiphertextInBytes[i]);
                }
                else if(counter>8)
                {
                    iResidue = counter % 8;
                    if(iResidue>0)
                        for(int i=0;i<iResidue;i++)
                            base64_func[(n++)%3](srcBytes[i]);
                }
                switch(n % 3)
                {
                case 1:
                    strEncode+= EncodeTable[(Tmp1 & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp1 & 0x03) << 4)];
                    strEncode+= "==";
                    break;
                case 2:
                    strEncode+= EncodeTable[(Tmp1 & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp1 & 0x03) << 4) | ((Tmp2 & 0xF0) >> 4)];
                    strEncode+= EncodeTable[((Tmp2 & 0x0F) << 2)];
                    strEncode+= "=";
                    break;
                }
                //  Remove the existing dictionary
                delete m_dictionary;
                char *pMem;
                hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strEncode.length()+1);
                if(hMem)
                {
                    pMem = (char*)GlobalLock(hMem);
                    strcpy(pMem,strEncode.c_str());
                    GlobalUnlock(hMem);
                    EmptyClipboard();
                    SetClipboardData(CF_TEXT,hMem);
                }
                CloseClipboard();
            }
        }
    }

    return nRetCode;
}
// encodeAESstr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "encodeAESstr.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;
using namespace std; 
//编码表
const char EncodeTable[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char Tmp1,Tmp2,Tmp3;
string strEncode;
int LineLength=0;
long n=0;
byte tmpRotWord[4];
byte tmpSubWord[4];
void set1st(unsigned char c)
{
    Tmp1 = c;
}

void set2nd(unsigned char c)
{
    Tmp2 = c;
}

void set3rd(unsigned char c)
{
    Tmp3 = c;
    strEncode+= EncodeTable[Tmp1 >> 2];
    strEncode+= EncodeTable[((Tmp1 << 4) | (Tmp2 >> 4)) & 0x3F];
    strEncode+= EncodeTable[((Tmp2 << 2) | (Tmp3 >> 6)) & 0x3F];
    strEncode+= EncodeTable[Tmp3 & 0x3F];
    if(LineLength+=4,LineLength==76) 
    {
        strEncode+="\r\n";
        LineLength=0;
    }
}

void (*base64_func[])(unsigned char c)={
    set1st,set2nd,set3rd
};

long counter=0;
unsigned char srcBytes[16];
unsigned char szLast16Bits[16];
unsigned char szCiphertextInBytes[16];
#define Bits128    16  
#define Bits192    24  
#define Bits256    32  

static unsigned char AesSbox[16*16]=  
{// populate the Sbox matrix  
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */  
    /*0*/  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,  
    /*1*/  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,  
    /*2*/  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,  
    /*3*/  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,  
    /*4*/  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,  
    /*5*/  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,  
    /*6*/  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,  
    /*7*/  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,  
    /*8*/  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,  
    /*9*/  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,  
    /*a*/  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,  
    /*b*/  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,  
    /*c*/  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,  
    /*d*/  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,  
    /*e*/  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,  
    /*f*/  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16  
};  

static unsigned char AesiSbox[16*16]=  
{  
    // populate the iSbox matrix  
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */  
    /*0*/  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,  
    /*1*/  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,  
    /*2*/  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,  
    /*3*/  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,  
    /*4*/  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,  
    /*5*/  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,  
    /*6*/  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,  
    /*7*/  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,  
    /*8*/  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,  
    /*9*/  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,  
    /*a*/  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,  
    /*b*/  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,  
    /*c*/  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,  
    /*d*/  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,  
    /*e*/  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,  
    /*f*/  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d  
};  
static unsigned char AesRcon[11*4]=  
{  
    0x00, 0x00, 0x00, 0x00,  
        0x01, 0x00, 0x00, 0x00,  
        0x02, 0x00, 0x00, 0x00,  
        0x04, 0x00, 0x00, 0x00,  
        0x08, 0x00, 0x00, 0x00,  
        0x10, 0x00, 0x00, 0x00,  
        0x20, 0x00, 0x00, 0x00,  
        0x40, 0x00, 0x00, 0x00,  
        0x80, 0x00, 0x00, 0x00,  
        0x1b, 0x00, 0x00, 0x00,  
        0x36, 0x00, 0x00, 0x00  
};  

unsigned char State[4][4];  
void Cipher(unsigned char* input, unsigned char* output);  // encipher 16-bit input  
void InvCipher(unsigned char* input, unsigned char* output);  // decipher 16-bit input  
int Nb;         // block size in 32-bit words.  Always 4 for AES.  (128 bits).  
int Nk;         // key size in 32-bit words.  4, 6, 8.  (128, 192, 256 bits).  
int Nr;         // number of rounds. 10, 12, 14.  

unsigned char key[32];
unsigned char w[16*15];

void SetNbNkNr(int keySize)  
{  
    Nb=4;  
    if(keySize=Bits128)  
    {  
        Nk=4;    //4*4字节,128位密钥,10轮加密  
        Nr=10;  
    }  
    else if(keySize=Bits192)  
    {  
        Nk=6;    //6*4字节,192位密钥,12轮加密  
        Nr=12;  
    }  
    else if(keySize=Bits256)  
    {  
        Nk=8;    //8*4字节,256位密钥,14轮加密  
        Nr=14;  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//密钥移位函数  
void RotWord(unsigned char word[])  
{    
    tmpRotWord[0] = word[1];  
    tmpRotWord[1] = word[2];  
    tmpRotWord[2] = word[3];  
    tmpRotWord[3] = word[0];  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//密钥字代换函数  
void SubWord(unsigned char word[])  
{ 
    for(int j=0;j<4;j++) 
        tmpSubWord[j] = AesSbox[16*(word[j] >> 4)+(word[j] & 0x0f)];  //实际上也可以写成AesSbox[[j]];因为两者相等  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
void KeyExpansion()  
{  
    int row;  
    memset(w,0,16*15);  
    for(row=0;row<Nk;row++)       //拷贝seed 密钥  
    {  
        w[4*row+0] =  key[4*row];  
        w[4*row+1] =  key[4*row+1];  
        w[4*row+2] =  key[4*row+2];  
        w[4*row+3] =  key[4*row+3];  
    }  
    unsigned char temp[4];  
    for(row=Nk;row<4*(Nr+1);row++)  
    {  
        temp[0]=w[4*row-4];     //当前列的前一列  
        temp[1]=w[4*row-3];  
        temp[2]=w[4*row-2];  
        temp[3]=w[4*row-1];  
        if(row%Nk==0)           //逢nk时,对当前列的前一列作特殊处理  
        {
            RotWord(temp);
            SubWord(tmpRotWord);   //先移位,再代换,最后和轮常量异或
            temp[0] = (byte)( (int)tmpSubWord[0] ^ (int) AesRcon[4*(row/Nk)+0] );  
            temp[1] = (byte)( (int)tmpSubWord[1] ^ (int) AesRcon[4*(row/Nk)+1] );  
            temp[2] = (byte)( (int)tmpSubWord[2] ^ (int) AesRcon[4*(row/Nk)+2] );  
            temp[3] = (byte)( (int)tmpSubWord[3] ^ (int) AesRcon[4*(row/Nk)+3] );  
        }  
        else if ( Nk > 6 && (row % Nk == 4) )  //这个还没有搞清楚 
        {
            SubWord(temp);
            temp[0]=tmpSubWord[0];
            temp[1]=tmpSubWord[1];
            temp[2]=tmpSubWord[2];
            temp[3]=tmpSubWord[3];
        }

        // w[row] = w[row-Nk] xor temp  
        w[4*row+0] = (byte) ( (int) w[4*(row-Nk)+0] ^ (int)temp[0] );  
        w[4*row+1] = (byte) ( (int) w[4*(row-Nk)+1] ^ (int)temp[1] );  
        w[4*row+2] = (byte) ( (int) w[4*(row-Nk)+2] ^ (int)temp[2] );  
        w[4*row+3] = (byte) ( (int) w[4*(row-Nk)+3] ^ (int)temp[3] );  
    }  // for loop
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//轮密钥加  
void AddRoundKey(int round)  
{  
    int i,j;  //i行 j列           //因为密钥w是一列一列排列的,即 k0 k4 k8 k12  
    for(j=0;j<4;j++)              //                              k1 k5 k9 k13  
    {                              //                              k2 k6 k10k14  
        for(i=0;i<4;i++)          //                              k3 k7 k11k15  
        {                          // 所以i行j列的下标是4*((round*4)+j)+i即16*round+4*j+i  
            State[i][j]=(unsigned char)((int)State[i][j]^(int)w[4*((round*4)+j)+i]);  
        }  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//字节代换函数  
void SubBytes()                              //Page 103  
{  
    int i,j;  
    for(j=0;j<4;j++)  
    {  
        for(i=0;i<4;i++)  
        {  
            State[i][j]=AesSbox[State[i][j]];  
            //因为 16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j]  
        }  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
void ShiftRows()  
{  
    unsigned char temp[4*4];                                        //Page105  
    int i,j;  
    for(j=0;j<4;j++)  
    {  
        for(i=0;i<4;i++)  
        {  
            temp[4*i+j]=State[i][j];  
        }  
    }  
    for(i=1;i<4;i++)  
    {  
        for(j=0;j<4;j++)  
        {  
            if(i==1)State[i][j]=temp[4*i+(j+1)%4];                    //第一行左移1位  
            else if(i==2)State[i][j]=temp[4*i+(j+2)%4];                //第二行左移2位  
            else if(i==3)State[i][j]=temp[4*i+(j+3)%4];                //第三行左移3位  
        }  
    }  

}  
////////////////////////////////////////////////////////////////////////////////////////////////  
unsigned char gfmultby01(unsigned char b)  
{  
    return b;  
}  
unsigned char gfmultby02(unsigned char b)  
{  
    if (b < 0x80)  
        return (unsigned char)(int)(b <<1);  
    else  
        return (unsigned char)( (int)(b << 1) ^ (int)(0x1b) );  
}  

unsigned char gfmultby03(unsigned char b)  
{  
    return (unsigned char) ( (int)gfmultby02(b) ^ (int)b );  
}  

unsigned char gfmultby09(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^ (int)b );  
}  

unsigned char gfmultby0b(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(b) ^ (int)b );  
}  

unsigned char gfmultby0d(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(gfmultby02(b)) ^ (int)(b) );  
}  

unsigned char gfmultby0e(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(gfmultby02(b)) ^(int)gfmultby02(b) );  
} 
////////////////////////////////////////////////////////////////////////////////////////////////  
void MixColumns()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for(j=0;j<4;j++)                                    //2 3 1 1  列混淆矩阵  Page107  
    {                                                    //1 2 3 1  
        for(i=0;i<4;i++)                                //1 1 2 3  
        {                                                //3 1 1 2  
            temp[4*i+j]=State[i][j];  
        }  
    }  
    for(j=0;j<4;j++)  
    {  
        State[0][j] = (unsigned char) ( (int)gfmultby02(temp[0+j]) ^ (int)gfmultby03(temp[4*1+j]) ^  
            (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );  
        State[1][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby02(temp[4*1+j]) ^  
            (int)gfmultby03(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );  
        State[2][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^  
            (int)gfmultby02(temp[4*2+j]) ^ (int)gfmultby03(temp[4*3+j]) );  
        State[3][j] = (unsigned char) ( (int)gfmultby03(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^  
            (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby02(temp[4*3+j]) );  
    }  

}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//Aes加密函数  
void Cipher(unsigned char* input, unsigned char* output)  
{  
    int i;  
    memset(&State[0][0],0,16);  
    for(i=0;i<4*Nb;i++)                        //这里是先写列后写行的,即输入是一列一列的进来的  
        State[i%4][i/4]=input[i];                    //换成先写行后写列也是可以的,只要在输出时也是这样就可以了  
    AddRoundKey(0);                                    //轮密钥加  

    for (int round = 1; round <= (Nr - 1); round++)  // main round loop  
    {  
        SubBytes();                                    //字节代换  
        ShiftRows();                                //行移位  
        MixColumns();                                //列混淆  
        AddRoundKey(round);                            //轮密钥加  
    }  // main round loop  

    SubBytes();                                        //字节代换  
    ShiftRows();                                    //行移位  
    AddRoundKey(Nr);                                //轮密钥加  

    // output = state  
    for (i = 0; i < (4 * Nb); i++)
        output[i] =  State[i % 4][ i / 4];
}  
void InvShiftRows()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for(j=0;j<4;j++)
        for(i=0;i<4;i++)
            temp[4*i+j]=State[i][j];
    for(i=1;i<4;i++)  
    {  
        for(j=0;j<4;j++)  
        {  
            //if(i==1)State[i][j]=temp[4*i+(j-1)%4];    在此犯了一个错误 -1%4=-1 而不是3,所以采用了下面再加一个4的做法  
            if(i==1)State[i][j]=temp[4*i+(j+3)%4];            //第一行右移1位 j-1+4=j+3  
            else if(i==2)State[i][j]=temp[4*i+(j+2)%4];        //第二行右移2位 j-2+4=j+2  
            else if(i==3)State[i][j]=temp[4*i+(j+1)%4];        //第三行右移3位 j-3+4=j+2  
        }  
    }  
}  
void InvSubBytes()  
{  
    int i,j;  
    for(j=0;j<4;j++)
        for(i=0;i<4;i++)
            State[i][j]=AesiSbox[State[i][j]]; //因为 16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j]  
}  
void InvMixColumns()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for (i = 0; i < 4; i++)  // copy State into temp[]  
    {  
        for (j = 0; j < 4; j++)                         //0e 0b 0d 09   逆变换矩阵 Page108  
        {                                                //09 0e 0b 0d  
            temp[4*i+j] =  State[i][j];                    //0d 09 0e 0b  
        }                                                //0b 0d 09 0e  
    }  

    for (j = 0; j < 4; j++)  
    {  
        State[0][j] = (unsigned char) ( (int)gfmultby0e(temp[j]) ^ (int)gfmultby0b(temp[4+j]) ^  
            (int)gfmultby0d(temp[4*2+j]) ^ (int)gfmultby09(temp[4*3+j]) );  
        State[1][j] = (unsigned char) ( (int)gfmultby09(temp[j]) ^ (int)gfmultby0e(temp[4+j]) ^  
            (int)gfmultby0b(temp[4*2+j]) ^ (int)gfmultby0d(temp[4*3+j]) );  
        State[2][j] = (unsigned char) ( (int)gfmultby0d(temp[j]) ^ (int)gfmultby09(temp[4+j]) ^  
            (int)gfmultby0e(temp[4*2+j]) ^ (int)gfmultby0b(temp[4*3+j]) );  
        State[3][j] = (unsigned char) ( (int)gfmultby0b(temp[j]) ^ (int)gfmultby0d(temp[4+j]) ^  
            (int)gfmultby09(temp[4*2+j]) ^ (int)gfmultby0e(temp[4*3+j]) );  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//Aes解密函数  
void InvCipher(unsigned char* input,unsigned char* output)  
{  
    int i;  
    memset(&State[0][0],0,16);  
    for (i = 0; i < (4 * Nb); i++)
        State[i % 4][ i / 4] = input[i];

    AddRoundKey(Nr);  

    for (int round = Nr-1; round >= 1; round--)  // main round loop  
    {  
        InvShiftRows();  
        InvSubBytes();  
        AddRoundKey(round);  
        InvMixColumns();  
    }  // end main round loop for InvCipher  

    InvShiftRows();  
    InvSubBytes();  
    AddRoundKey(0);  

    // output = state  
    for (i = 0; i < (4 * Nb); i++)
        output[i] =  State[i % 4][ i / 4];
}

void aes_deal(int idx,char c)
{
    srcBytes[15]=c;
    memcpy(szLast16Bits,srcBytes,16);
    Cipher((unsigned char*)szLast16Bits,(unsigned char*)szCiphertextInBytes);
    for(int i=0;i<16;i++)
        base64_func[(n++)%3](szCiphertextInBytes[i]);
}

void aes_store(int idx,char c)
{
    srcBytes[idx]=c;
}

void (*aes_func[])(int idx,char c)={
    aes_store,aes_deal
};

void aes_adpter(char c)
{
    int idx=(counter++)%16;
    aes_func[counter%16==0](idx,c);
}

BYTE m_MaxBits = 9;
int m_TotalBits = 0;
DWORD m_SavedData = 0;
struct dicElement
{
    DWORD   m_Prefix;       //  keep the prefix of the element
    BYTE    m_Letter;       //  keep the letter of the element

    dicElement()
    {
        m_Prefix = 0;
        m_Letter = 0;
    }
};
void GetBytesFromCode(CPtrArray *m_dictionary,CByteArray *Buffer, DWORD code)
{
    //  Fill an array with bytes using the code for retrieving 
    //  those bytes from the dictionary elements

    //  Since we dont have 0-255 in the dictionary we have to make 
    //  sure, that if we get below 256 we stop (but still add that code)
    //  Every code higher then 255, will have a letter attached to it,
    //  which we use for getting the string back.

    while (code > 255)
    {
        dicElement *tmpEl = (dicElement*)m_dictionary->GetAt(code - 256);
        Buffer->Add(tmpEl->m_Letter);
        code = tmpEl->m_Prefix;
    }
    Buffer->Add((BYTE)code);
}

void CompressData(DWORD toSave)
{
    //  Move the data you want to write few bits to the left
    //  and combine it with the already existing data in the buffer
    m_SavedData |= toSave << (32 - m_MaxBits - m_TotalBits);
    //  Add the new added number of bits to the total bits counter
    m_TotalBits += m_MaxBits;
    //  Check if it's possible to enter the data to the file
    //  (over and equal a byte of data)
    while (m_TotalBits >= 8)
    {
        //  Get the byte we want to write
        DWORD writeData = m_SavedData;
        writeData >>= 24;
        aes_adpter(writeData);
        //  remove the byte from the buffer
        m_SavedData <<= 8;
        //  Remove the byte from the counter
        m_TotalBits -= 8;
    }
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        cerr << _T("Fatal Error: MFC initialization failed") << endl;
        nRetCode = 1;
    }
    else
    {
        if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) //CF_UNICODETEXT
        {
            HGLOBAL hMem = GetClipboardData(CF_TEXT); 
            if (hMem != NULL) 
            {
                LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 
                if (lpStr != NULL)
                    GlobalUnlock(hMem);
                //加密操作  
                unsigned char* keyBytes=(unsigned char*)"12345678123456781234567812345678";
                SetNbNkNr(32);                         //设置密钥块数,轮数  
                memcpy(key,keyBytes,32);                //字符串拷贝函数,把keyBytes的keysize个字符复制到key中  
                KeyExpansion();                                //密钥扩展,必须提前做的初始化
                DWORD m_MaxCode[32]={0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF,0x1FFFF,0x3FFFF,0x7FFFF,0xFFFFF,0x1FFFFF,0x3FFFFF,0x7FFFFF,0xFFFFFF,0x1FFFFFF,0x3FFFFFF,0x7FFFFFF,0xFFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF};
                CPtrArray *m_dictionary= new CPtrArray;
                long result = 0;
                BYTE readByte = 0;
                CString logString;
                DWORD resAdd = 256;
                //  Get the total file size
                DWORD prefix=*lpStr++;
                //  Go over the rest of the file and read it
                while (readByte=*lpStr++)
                {
                    //  Check if the prefix and readByte combination exist in the dictionary
                    //  Returns the code of an element from the dictionary
                    //  by searching for the prefix and letter assosiated with
                    //  that element code.
                    //  Returns -1 if no entry was found
                    int total = m_dictionary->GetSize();
                    dicElement *temp = NULL;
                    for (int counter = 0; counter < total; counter++)
                    {
                        temp = (dicElement*)m_dictionary->GetAt(counter);
                        if ((temp->m_Prefix == prefix) && 
                            (temp->m_Letter == readByte))
                            break;
                        temp = NULL;
                    }
                    if (temp != NULL)
                        result =counter + 256;
                    else
                        result =-1;
                    //  If not exist
                    if (result == -1)
                    {
                        //  Add the new combination
                        //  Add a dictionary element.
                        //  Since the dictionary should already have all the values
                        //  between 0-255, we start it from 256.
                        dicElement *temp = new dicElement;
                        temp->m_Prefix = prefix;
                        temp->m_Letter = readByte;
                        m_dictionary->Add(temp);
                        resAdd = m_dictionary->GetSize() + 255;
                        //  Calculate the new bit size needed to encode the file
                        //  Check the value of the parameter against the Maximum number possible
                        //  and then returns the counter
                        //  This can also be acheived by right shifting the value until we get 0
                        //  and counting the number of times we doing it.
                        for (BYTE counter = 0; counter < 32; counter++)
                            if (resAdd <= m_MaxCode[counter])
                                break;
                        m_MaxBits = counter;
                        //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
                        //  then the minimal number of bits is check to return a 9 in case a lower value will be
                        //  reached in the application
                        if (m_MaxBits < 9)
                            m_MaxBits = 9;  
                        //  Send the prefix for compression in to the destination file
                        CompressData(prefix);
                        //  Set the prefix as the readByte
                        prefix = readByte;
                        //  Initiate the result
                        result = -1;
                        delete temp;
                    }
                    else
                    {
                        //  Set the prefix as the result
                        prefix = result;
                        readByte = 0;
                    }
                }
                //  Insert to the file the maximum number of bit (for signaling the end of the
                //  compression\decompression)
                CompressData(prefix);
                CompressData(m_MaxCode[m_MaxBits]);
                //  Flash the rest of the file with 0
                CompressData(0);
                int iParts=0,iResidue=0,i=0;
                unsigned char szLast16Bits[16] = {0};
                if(counter<16)
                {
                    unsigned char _temp16bytes[16] = {0};
                    memcpy(_temp16bytes,srcBytes,counter);
                    Cipher(_temp16bytes,szCiphertextInBytes);
                    for(int i=0;i<16;i++)
                        base64_func[(n++)%3](szCiphertextInBytes[i]);
                }
                else if(counter>16)
                {
                    iResidue = counter % 16;
                    if(iResidue>0)
                        for(int i=0;i<iResidue;i++)
                            base64_func[(n++)%3](srcBytes[i]);
                }
                switch(n % 3)
                {
                case 1:
                    strEncode+= EncodeTable[(Tmp1 & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp1 & 0x03) << 4)];
                    strEncode+= "==";
                    break;
                case 2:
                    strEncode+= EncodeTable[(Tmp1 & 0xFC) >> 2];
                    strEncode+= EncodeTable[((Tmp1 & 0x03) << 4) | ((Tmp2 & 0xF0) >> 4)];
                    strEncode+= EncodeTable[((Tmp2 & 0x0F) << 2)];
                    strEncode+= "=";
                    break;
                }
                //  Remove the existing dictionary
                delete m_dictionary;
                char *pMem;
                hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strEncode.length()+1);
                if(hMem)
                {
                    pMem = (char*)GlobalLock(hMem);
                    strcpy(pMem,strEncode.c_str());
                    GlobalUnlock(hMem);
                    EmptyClipboard();
                    SetClipboardData(CF_TEXT,hMem);
                }
                CloseClipboard();
            }
        }
    }

    return nRetCode;
}

0x01
编译一个debug版本的UPX

decodeDESstr.cpp

decodeAESstr.cpp

UPX for
Linux的源码位于其git仓库地址https://github.com/upx/upx.git 中,使用git工具或者直接在浏览器中打开页面就可以获取其源码文件。为了方便学习,我编译了一个debug版本的UPX4debug

// decodeDESstr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "decodeDESstr.h"
#include <string.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;
void decompress_adpter(BYTE b);
DWORD m_MaxCode[32]={0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF,0x1FFFF,0x3FFFF,0x7FFFF,0xFFFFF,0x1FFFFF,0x3FFFFF,0x7FFFFF,0xFFFFFF,0x1FFFFFF,0x3FFFFFF,0x7FFFFFF,0xFFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF};
BYTE m_MaxBits= 9;
int m_TotalBits= 0;
DWORD m_SavedData= 0;
DWORD data = 0;
CByteArray decodeString;
BYTE writeData = 0, character = 0;
long counter = 0;
//  Get the first prefix information
DWORD prefix;
int idx=0;
CPtrArray *m_dictionary;
string strDecode;
struct dicElement
{
    DWORD   m_Prefix;       //  keep the prefix of the element
    BYTE    m_Letter;       //  keep the letter of the element

    dicElement()
    {
        m_Prefix = 0;
        m_Letter = 0;
    }
};

void GetBytesFromCode(CPtrArray *m_dictionary,CByteArray *Buffer, DWORD code)
{
    //  Fill an array with bytes using the code for retrieving 
    //  those bytes from the dictionary elements

    //  Since we dont have 0-255 in the dictionary we have to make 
    //  sure, that if we get below 256 we stop (but still add that code)
    //  Every code higher then 255, will have a letter attached to it,
    //  which we use for getting the string back.
    dicElement *tmpEl = NULL;

    while (code > 255)
    {
        tmpEl = (dicElement*)m_dictionary->GetAt(code - 256);
        Buffer->Add(tmpEl->m_Letter);
        code = tmpEl->m_Prefix;
    }
    Buffer->Add((BYTE)code);
}

void getbyte(BYTE b)
{   
    //  Add the byte to the read buffer
    m_SavedData |= (DWORD) b << (24 - m_TotalBits);
    //  Add byte to the bit counter
    m_TotalBits += 8;
}

void initial(BYTE b)
{
    idx=1;
    //  calculate the return information
    prefix = m_SavedData >> (32 - m_MaxBits);
    //  Remove the returned information from the buffer
    m_SavedData <<= m_MaxBits;
    //  Remove the return information bit size from the bit counter
    m_TotalBits -= m_MaxBits;
    //  Save the prefix as the last used character (since we're writing it in the
    //  destination file)
    character = (BYTE)prefix;
    //  Write the prefix in the destination file (the first byte inside
    //  a LZW copressed file is always the first byte of the original file)
    strDecode+=prefix;
    decompress_adpter(b);
}

void rest2(BYTE b)
{
    //  calculate the return information
    data = m_SavedData >> (32 - m_MaxBits);
    //  Remove the returned information from the buffer
    m_SavedData <<= m_MaxBits;
    //  Remove the return information bit size from the bit counter
    m_TotalBits -= m_MaxBits;

    if (data != m_MaxCode[m_MaxBits])
    {
        //  Check if the code exist in the dictionary
        //  if not
        //  Check if the code exist in the dictionary
        //  Returns TRUE if so, and FALSE if not.

        //  If the code is lower then 256, then the element is a normal
        //  ASCII character, and as such is considered to be in the
        //  dictionay.
        if (data >= 256 && data - 256 >= (unsigned)m_dictionary->GetSize())
        {
            //  Get the last used character into the decod buffer
            decodeString.Add((BYTE)character);
            //  Decode the existing prefix into a known string of data
            GetBytesFromCode(m_dictionary,&decodeString, prefix);
        }
        else
        {
            //  Decode the data into the decode buffer
            GetBytesFromCode(m_dictionary,&decodeString, data);
            //  Get the last letter inside the data, as the last used letter
            character = decodeString.GetAt(decodeString.GetSize() - 1);
        }

        //  Go over the decode buffer, from the end to the start,
        //  and write the information into the destination file
        counter = decodeString.GetSize();
        while (counter > 0)
        {
            writeData = (BYTE)decodeString.GetAt(--counter);
            strDecode+=writeData;
        }

        //  Clear the decode buffer
        decodeString.RemoveAll();
        //  Add the new combination into the dictionary
        //  Add a dictionary element.
        //  Since the dictionary should already have all the values
        //  between 0-255, we start it from 256.
        dicElement *tmp = new dicElement;

        tmp->m_Prefix = prefix;
        tmp->m_Letter = (BYTE)character;

        m_dictionary->Add(tmp);

        //  Calculate the new buffer size to read now
        DWORD value=m_dictionary->GetSize() + 257;
        //  Check the value of the parameter against the Maximum number possible
        //  and then returns the counter

        //  This can also be acheived by right shifting the value until we get 0
        //  and counting the number of times we doing it.

        for (BYTE counter = 0; counter < 32; counter++)
            if (value <= m_MaxCode[counter])
                break;
        m_MaxBits = counter;

        //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
        //  then the minimal number of bits is check to return a 9 in case a lower value will be
        //  reached in the application
        if (m_MaxBits < 9)
            m_MaxBits = 9;              
        //  Set the new prefix to use
        prefix = data;
        delete tmp;
    }
}

void (*rest_func[])(BYTE b)={
    getbyte,rest2
};

void rest(BYTE b)
{
    rest_func[m_TotalBits > 24](b);
    decompress_adpter(b);
}

void (*getrestbytes[])(BYTE b)={
    initial,rest
};

void getotherbytes(BYTE b)
{
    getrestbytes[idx](b);
}

void (*decompress_func[])(BYTE b)={
    getbyte,getotherbytes
};

void decompress_adpter(BYTE b)
{
    decompress_func[m_TotalBits > 24](b);
}

long count=0;
char srcBytes[8]={0};
char szLast8Bits[8] = {0};
char szSubKeys[16][48];//储存16组48位密钥
char szCiphertextRaw[64]; //储存二进制密文(64个Bits) int 0,1
char szPlaintextRaw[64]; //储存二进制密文(64个Bits) int 0,1
char szCiphertextInBytes[8];//储存8位密文
char szPlaintextInBytes[8];//储存8位明文字符串
char szPlaintext[9];//储存8位明文字符串,最后一位存'\0'

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

void DES_CreateSubKey(char* sz_56key)
{
    char szTmpL[28] = {0};
    char szTmpR[28] = {0};
    char szCi[28] = {0};
    char szDi[28] = {0};
    char szTmp56[56] = {0};
    int i=0,j=0;

    memcpy(szTmpL,sz_56key,28);
    memcpy(szTmpR,sz_56key + 28,28);

    for(i=0;i<16;i++)
    {
        //shift to left
        //Left 28 bits
        memcpy(szCi,szTmpL + Shift_Table[i],28 - Shift_Table[i]);
        memcpy(szCi + 28 - Shift_Table[i],szTmpL,Shift_Table[i]);
        //Right 28 bits
        memcpy(szDi,szTmpR + Shift_Table[i],28 - Shift_Table[i]);
        memcpy(szDi + 28 - Shift_Table[i],szTmpR,Shift_Table[i]);

        //permuted choice 48 bits key
        memcpy(szTmp56,szCi,28);
        memcpy(szTmp56 + 28,szDi,28);
        for(j=0;j<48;j++)
            szSubKeys[i][j] = szTmp56[PC2_Table[j]-1];
        //Evaluate new szTmpL and szTmpR
        memcpy(szTmpL,szCi,28);
        memcpy(szTmpR,szDi,28);
    }
}

void DES_Bytes2Bits(char *srcBytes, char* dstBits, unsigned int sizeBits)
{
    unsigned int i=0;
    for(i=0; i < sizeBits; i++)
        dstBits[i] = ((srcBytes[i>>3]<<(i&7)) & 128)>>7;
}

void DES_InitializeKey(char* srcBytes)
{
    //convert 8 char-bytes key to 64 binary-bits
    char sz_64key[64] = {0};
    char sz_56key[56] = {0};
    int k=0;
    DES_Bytes2Bits(srcBytes,sz_64key,64);
    //PC 1
    for(k=0;k<56;k++)
        sz_56key[k] = sz_64key[PC1_Table[k]-1];
    DES_CreateSubKey(sz_56key);
}

void DES_InitialPermuteData(char* _src,char* _dst)
{
    //IP
    int i=0;
    for(i=0;i<64;i++)
        _dst[i] = _src[IP_Table[i]-1];
}

void DES_XOR(char* szParam1,char* szParam2, unsigned int uiParamLength, char* szReturnValueBuffer)
{
    unsigned int i=0;
    for(i=0; i<uiParamLength; i++)
        szReturnValueBuffer[i] = szParam1[i] ^ szParam2[i];
}

void DES_ExpansionR(char* _src,char* _dst)
{
    int i=0;
    for(i=0;i<48;i++)
        _dst[i] = _src[E_Table[i]-1];
}

void DES_Int2Bits(unsigned int _src, char* dstBits)
{
    unsigned int i=0;
    for(i=0; i < 4; i++)
        dstBits[i] = ((_src<<i) & 8)>>3;
}

void DES_CompressFuncS(char* _src48, char* _dst32)
{
    char bTemp[8][6]={0};
    char dstBits[4]={0};
    int i=0,iX=0,iY=0,j=0;

    for(i=0;i<8;i++)
    {
        memcpy(bTemp[i],_src48+i*6,6);
        iX = (bTemp[i][0])*2 + (bTemp[i][5]);
        iY = 0;
        for(j=1;j<5;j++)
            iY += bTemp[i][j]<<(4-j);
        DES_Int2Bits(S_Box[i][iX][iY], dstBits);
        memcpy(_dst32 + i * 4, dstBits, 4);
    }

}

void DES_PermutationP(char* _src,char* _dst)
{
    int i=0;
    for(i=0;i<32;i++)
        _dst[i] = _src[P_Table[i]-1];
}

void DES_FunctionF(char* sz_Li,char* sz_Ri,unsigned int iKey)
{
    char sz_48R[48] = {0};
    char sz_xor48[48] = {0};
    char sz_P32[32] = {0};
    char sz_Rii[32] = {0};
    char sz_Key[48] = {0};
    char s_Compress32[32] = {0};
    memcpy(sz_Key,szSubKeys[iKey],48);
    DES_ExpansionR(sz_Ri,sz_48R);
    DES_XOR(sz_48R,sz_Key,48,sz_xor48);

    DES_CompressFuncS(sz_xor48,s_Compress32);
    DES_PermutationP(s_Compress32,sz_P32);
    DES_XOR(sz_P32,sz_Li,32,sz_Rii);
    memcpy(sz_Li,sz_Ri,32);
    memcpy(sz_Ri,sz_Rii,32);
}

void DES_Bits2Bytes(char *dstBytes, char* srcBits, unsigned int sizeBits)
{
    unsigned int i=0;
    memset(dstBytes,0,sizeBits>>3);
    for(i=0; i < sizeBits; i++)
        dstBytes[i>>3] |= (srcBits[i] << (7 - (i & 7)));
}

void DES_DecryptData(char* _srcBytes)
{
    char szSrcBits[64] = {0};
    char sz_IP[64] = {0};
    char sz_Li[32] = {0};
    char sz_Ri[32] = {0};
    char sz_Final64[64] = {0};
    int i=0,j=0;
    DES_Bytes2Bits(_srcBytes,szSrcBits,64);
    //IP --- return is sz_IP
    DES_InitialPermuteData(szSrcBits,sz_IP);
    //divide the 64 bits data to two parts
    memcpy(sz_Ri,sz_IP,32); //exchange L to R
    memcpy(sz_Li,sz_IP + 32,32);  //exchange R to L
    //16 rounds F and xor and exchange
    for(i=0;i<16;i++)
        DES_FunctionF(sz_Ri,sz_Li,15-i);
    memcpy(sz_Final64,sz_Li,32);
    memcpy(sz_Final64 + 32,sz_Ri,32);
    // ~IP
    for(j=0;j<64;j++)
        szPlaintextRaw[j] = sz_Final64[IPR_Table[j]-1];
    DES_Bits2Bytes(szPlaintextInBytes,szPlaintextRaw,64);
}

void inv_des_deal(int idx,char c)
{
    srcBytes[7]=c;
    memcpy(szLast8Bits,srcBytes,8);
    DES_DecryptData(szLast8Bits);
    for(int ii=0;ii<8;ii++)
        decompress_adpter(szPlaintextInBytes[ii]);
}

void inv_des_store(int idx,char c)
{
    srcBytes[idx]=c;
}

void (*inv_des_func[])(int idx,char c)={
    inv_des_store,inv_des_deal
};

void inv_des_adpter(char c)
{
    int idx=(count++)%8;
    inv_des_func[count%8==0](idx,c);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        cerr << _T("Fatal Error: MFC initialization failed") << endl;
        nRetCode = 1;
    }
    else
    {
        if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) //CF_UNICODETEXT
        {
            HGLOBAL hMem = GetClipboardData(CF_TEXT); 
            if (hMem != NULL) 
            {
                LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 
                if (lpStr != NULL)
                    GlobalUnlock(hMem);
                DES_InitializeKey("dsdfgsff");
                TCHAR* Data=lpStr;
                int DataByte=strlen(lpStr);
                m_dictionary= new CPtrArray;
                //解码表
                TCHAR DecodeTable[] =
                {
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        62, // '+'
                        0, 0, 0,
                        63, // '/'
                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
                        0, 0, 0, 0, 0, 0, 0,
                        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
                        0, 0, 0, 0, 0, 0,
                        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
                        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
                };
                int nValue;
                int i= 0;
                while (i < DataByte)
                {
                    if (*Data != '\r' && *Data!='\n')
                    {
                        nValue = DecodeTable[*Data++] << 18;
                        nValue += DecodeTable[*Data++] << 12;
                        inv_des_adpter((nValue & 0x00FF0000) >> 16);
                        if (*Data != '=')
                        {
                            nValue += DecodeTable[*Data++] << 6;
                            inv_des_adpter((nValue & 0x0000FF00) >> 8);
                            if (*Data != '=')
                            {
                                nValue += DecodeTable[*Data++];
                                inv_des_adpter(nValue & 0x000000FF);
                            }
                        }
                        i += 4;
                    }
                    else// 回车换行,跳过
                    {
                        Data++;
                        i++;
                    }
                }
                char szLast8Bits[8] = {0};
                char _temp8bytes[8] = {0};
                if(count<8)
                {
                    memcpy(_temp8bytes,srcBytes,8);
                    DES_DecryptData(_temp8bytes);
                    for(int ii=0;ii<8;ii++)
                        decompress_adpter(szPlaintextInBytes[ii]);
                }
                else if(count>8)
                {
                    int iResidue = count % 8;
                    if(iResidue>0)
                        for(int ii=0;ii<iResidue;ii++)
                            decompress_adpter(srcBytes[ii]);
                }
                for(data=(m_SavedData == 0 && m_TotalBits == 0)?m_MaxCode[m_MaxBits]:m_SavedData >> (32 - m_MaxBits),m_SavedData <<= m_MaxBits,m_TotalBits -= m_MaxBits;
                data != m_MaxCode[m_MaxBits];
                data=(m_SavedData == 0 && m_TotalBits == 0)?m_MaxCode[m_MaxBits]:m_SavedData >> (32 - m_MaxBits),m_SavedData <<= m_MaxBits,m_TotalBits -= m_MaxBits)
                {
                    //  Check if the code exist in the dictionary
                    //  if not
                    //  Check if the code exist in the dictionary
                    //  Returns TRUE if so, and FALSE if not.

                    //  If the code is lower then 256, then the element is a normal
                    //  ASCII character, and as such is considered to be in the
                    //  dictionay.
                    if (data >= 256 && data - 256 >= (unsigned)m_dictionary->GetSize())
                    {
                        //  Get the last used character into the decod buffer
                        decodeString.Add((BYTE)character);
                        //  Decode the existing prefix into a known string of data
                        GetBytesFromCode(m_dictionary,&decodeString, prefix);
                    }
                    else
                    {
                        //  Decode the data into the decode buffer
                        GetBytesFromCode(m_dictionary,&decodeString, data);
                        //  Get the last letter inside the data, as the last used letter
                        character = decodeString.GetAt(decodeString.GetSize() - 1);
                    }

                    //  Go over the decode buffer, from the end to the start,
                    //  and write the information into the destination file
                    counter = decodeString.GetSize();
                    while (counter > 0)
                    {
                        writeData = (BYTE)decodeString.GetAt(--counter);
                        strDecode+=writeData;
                    }

                    //  Clear the decode buffer
                    decodeString.RemoveAll();
                    //  Add the new combination into the dictionary
                    //  Add a dictionary element.
                    //  Since the dictionary should already have all the values
                    //  between 0-255, we start it from 256.
                    dicElement *tmp = new dicElement;

                    tmp->m_Prefix = prefix;
                    tmp->m_Letter = (BYTE)character;

                    m_dictionary->Add(tmp);

                    //  Calculate the new buffer size to read now
                    DWORD value=m_dictionary->GetSize() + 257;
                    //  Check the value of the parameter against the Maximum number possible
                    //  and then returns the counter

                    //  This can also be acheived by right shifting the value until we get 0
                    //  and counting the number of times we doing it.

                    for (BYTE counter = 0; counter < 32; counter++)
                        if (value <= m_MaxCode[counter])
                            break;
                    m_MaxBits = counter;

                    //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
                    //  then the minimal number of bits is check to return a 9 in case a lower value will be
                    //  reached in the application
                    if (m_MaxBits < 9)
                        m_MaxBits = 9;              
                    //  Set the new prefix to use
                    prefix = data;
                    delete tmp;
                }
                delete m_dictionary;
                char *pMem;
                hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strDecode.length()+1);
                if(hMem)
                {
                    pMem = (char*)GlobalLock(hMem);
                    strcpy(pMem,strDecode.c_str());
                    GlobalUnlock(hMem);
                    EmptyClipboard();
                    SetClipboardData(CF_TEXT,hMem);
                }
                CloseClipboard();
            }
        }
    }

    return nRetCode;
}
// decodeAESstr.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "decodeAESstr.h"
#include <string>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;
using namespace std;

DWORD m_MaxCode[32]={0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF,0x1FFFF,0x3FFFF,0x7FFFF,0xFFFFF,0x1FFFFF,0x3FFFFF,0x7FFFFF,0xFFFFFF,0x1FFFFFF,0x3FFFFFF,0x7FFFFFF,0xFFFFFFF,0x1FFFFFFF,0x3FFFFFFF,0x7FFFFFFF};
BYTE m_MaxBits= 9;
int m_TotalBits= 0;
DWORD m_SavedData= 0;
DWORD data = 0;
CByteArray decodeString;
BYTE writeData = 0, character = 0;
long counter=0;
long count=0;
unsigned char srcBytes[32];
unsigned char szLast16Bits[32];
unsigned char szPlaintextInBytes[32];
//  Get the first prefix information
DWORD prefix;
BYTE readByte;
int idx=0;
CPtrArray *m_dictionary;
string strDecode;
void decompress_adpter(BYTE b);
byte tmpRotWord[4];
byte tmpSubWord[4];
struct dicElement
{
    DWORD   m_Prefix;       //  keep the prefix of the element
    BYTE    m_Letter;       //  keep the letter of the element

    dicElement()
    {
        m_Prefix = 0;
        m_Letter = 0;
    }
};

void GetBytesFromCode(CPtrArray *m_dictionary,CByteArray *Buffer, DWORD code)
{
    //  Fill an array with bytes using the code for retrieving 
    //  those bytes from the dictionary elements

    //  Since we dont have 0-255 in the dictionary we have to make 
    //  sure, that if we get below 256 we stop (but still add that code)
    //  Every code higher then 255, will have a letter attached to it,
    //  which we use for getting the string back.
    dicElement *tmpEl = NULL;

    while (code > 255)
    {
        tmpEl = (dicElement*)m_dictionary->GetAt(code - 256);
        Buffer->Add(tmpEl->m_Letter);
        code = tmpEl->m_Prefix;
    }
    Buffer->Add((BYTE)code);
}

void getbyte(BYTE b)
{   
    //  Add the byte to the read buffer
    m_SavedData |= (DWORD) b << (24 - m_TotalBits);
    //  Add byte to the bit counter
    m_TotalBits += 8;
}

void initial(BYTE b)
{
    idx=1;
    //  calculate the return information
    prefix = m_SavedData >> (32 - m_MaxBits);
    //  Remove the returned information from the buffer
    m_SavedData <<= m_MaxBits;
    //  Remove the return information bit size from the bit counter
    m_TotalBits -= m_MaxBits;
    //  Save the prefix as the last used character (since we're writing it in the
    //  destination file)
    character = (BYTE)prefix;
    //  Write the prefix in the destination file (the first byte inside
    //  a LZW copressed file is always the first byte of the original file)
    strDecode+=prefix;
    decompress_adpter(b);
}

void rest2(BYTE b)
{
    //  calculate the return information
    data = m_SavedData >> (32 - m_MaxBits);
    //  Remove the returned information from the buffer
    m_SavedData <<= m_MaxBits;
    //  Remove the return information bit size from the bit counter
    m_TotalBits -= m_MaxBits;

    if (data != m_MaxCode[m_MaxBits])
    {
        //  Check if the code exist in the dictionary
        //  if not
        //  Check if the code exist in the dictionary
        //  Returns TRUE if so, and FALSE if not.

        //  If the code is lower then 256, then the element is a normal
        //  ASCII character, and as such is considered to be in the
        //  dictionay.
        if (data >= 256 && data - 256 >= (unsigned)m_dictionary->GetSize())
        {
            //  Get the last used character into the decod buffer
            decodeString.Add((BYTE)character);
            //  Decode the existing prefix into a known string of data
            GetBytesFromCode(m_dictionary,&decodeString, prefix);
        }
        else
        {
            //  Decode the data into the decode buffer
            GetBytesFromCode(m_dictionary,&decodeString, data);
            //  Get the last letter inside the data, as the last used letter
            character = decodeString.GetAt(decodeString.GetSize() - 1);
        }

        //  Go over the decode buffer, from the end to the start,
        //  and write the information into the destination file
        counter = decodeString.GetSize();
        while (counter > 0)
        {
            writeData = (BYTE)decodeString.GetAt(--counter);
            strDecode+=writeData;
            //  To show a log in the view
        }

        //  Clear the decode buffer
        decodeString.RemoveAll();
        //  Add the new combination into the dictionary
        //  Add a dictionary element.
        //  Since the dictionary should already have all the values
        //  between 0-255, we start it from 256.
        dicElement *tmp = new dicElement;

        tmp->m_Prefix = prefix;
        tmp->m_Letter = (BYTE)character;

        m_dictionary->Add(tmp);

        //  Calculate the new buffer size to read now
        DWORD value=m_dictionary->GetSize() + 257;
        //  Check the value of the parameter against the Maximum number possible
        //  and then returns the counter

        //  This can also be acheived by right shifting the value until we get 0
        //  and counting the number of times we doing it.

        for (BYTE counter = 0; counter < 32; counter++)
            if (value <= m_MaxCode[counter])
                break;
        m_MaxBits = counter;

        //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
        //  then the minimal number of bits is check to return a 9 in case a lower value will be
        //  reached in the application
        if (m_MaxBits < 9)
            m_MaxBits = 9;              
        //  Set the new prefix to use
        prefix = data;
        delete tmp;
    }
}

void (*rest_func[])(BYTE b)={
    getbyte,rest2
};

void rest(BYTE b)
{
    rest_func[m_TotalBits > 24](b);
    decompress_adpter(b);
}

void (*getrestbytes[])(BYTE b)={
    initial,rest
};

void getotherbytes(BYTE b)
{
    getrestbytes[idx](b);
}

void (*decompress_func[])(BYTE b)={
    getbyte,getotherbytes
};

void decompress_adpter(BYTE b)
{
    decompress_func[m_TotalBits > 24](b);
}

#define Bits128    16  
#define Bits192    24  
#define Bits256    32  

static unsigned char AesSbox[16*16]=  
{// populate the Sbox matrix  
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */  
    /*0*/  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,  
    /*1*/  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,  
    /*2*/  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,  
    /*3*/  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,  
    /*4*/  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,  
    /*5*/  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,  
    /*6*/  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,  
    /*7*/  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,  
    /*8*/  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,  
    /*9*/  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,  
    /*a*/  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,  
    /*b*/  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,  
    /*c*/  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,  
    /*d*/  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,  
    /*e*/  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,  
    /*f*/  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16  
};  

static unsigned char AesiSbox[16*16]=  
{  
    // populate the iSbox matrix  
    /* 0     1     2     3     4     5     6     7     8     9     a     b     c     d     e     f */  
    /*0*/  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,  
    /*1*/  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,  
    /*2*/  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,  
    /*3*/  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,  
    /*4*/  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,  
    /*5*/  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,  
    /*6*/  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,  
    /*7*/  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,  
    /*8*/  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,  
    /*9*/  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,  
    /*a*/  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,  
    /*b*/  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,  
    /*c*/  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,  
    /*d*/  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,  
    /*e*/  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,  
    /*f*/  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d  
};  
static unsigned char AesRcon[11*4]=  
{  
    0x00, 0x00, 0x00, 0x00,  
        0x01, 0x00, 0x00, 0x00,  
        0x02, 0x00, 0x00, 0x00,  
        0x04, 0x00, 0x00, 0x00,  
        0x08, 0x00, 0x00, 0x00,  
        0x10, 0x00, 0x00, 0x00,  
        0x20, 0x00, 0x00, 0x00,  
        0x40, 0x00, 0x00, 0x00,  
        0x80, 0x00, 0x00, 0x00,  
        0x1b, 0x00, 0x00, 0x00,  
        0x36, 0x00, 0x00, 0x00  
};  

unsigned char State[4][4];  
void InvCipher(unsigned char* input, unsigned char* output);  // decipher 16-bit input  
int Nb;         // block size in 32-bit words.  Always 4 for AES.  (128 bits).  
int Nk;         // key size in 32-bit words.  4, 6, 8.  (128, 192, 256 bits).  
int Nr;         // number of rounds. 10, 12, 14.  

unsigned char key[32];
unsigned char w[16*15];

void SetNbNkNr(int keySize)  
{  
    Nb=4;  
    if(keySize=Bits128)  
    {  
        Nk=4;    //4*4字节,128位密钥,10轮加密  
        Nr=10;  
    }  
    else if(keySize=Bits192)  
    {  
        Nk=6;    //6*4字节,192位密钥,12轮加密  
        Nr=12;  
    }  
    else if(keySize=Bits256)  
    {  
        Nk=8;    //8*4字节,256位密钥,14轮加密  
        Nr=14;  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//密钥移位函数  
void RotWord(unsigned char word[])  
{    
    tmpRotWord[0] = word[1];  
    tmpRotWord[1] = word[2];  
    tmpRotWord[2] = word[3];  
    tmpRotWord[3] = word[0];  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//密钥字代换函数  
void SubWord(unsigned char word[])  
{ 
    for(int j=0;j<4;j++) 
        tmpSubWord[j] = AesSbox[16*(word[j] >> 4)+(word[j] & 0x0f)];  //实际上也可以写成AesSbox[[j]];因为两者相等  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
void KeyExpansion()  
{  
    int row;  
    memset(w,0,16*15);  
    for(row=0;row<Nk;row++)       //拷贝seed 密钥  
    {  
        w[4*row+0] =  key[4*row];  
        w[4*row+1] =  key[4*row+1];  
        w[4*row+2] =  key[4*row+2];  
        w[4*row+3] =  key[4*row+3];  
    }  
    unsigned char temp[4];  
    for(row=Nk;row<4*(Nr+1);row++)  
    {  
        temp[0]=w[4*row-4];     //当前列的前一列  
        temp[1]=w[4*row-3];  
        temp[2]=w[4*row-2];  
        temp[3]=w[4*row-1];  
        if(row%Nk==0)           //逢nk时,对当前列的前一列作特殊处理  
        {
            RotWord(temp);
            SubWord(tmpRotWord);   //先移位,再代换,最后和轮常量异或
            temp[0] = (byte)( (int)tmpSubWord[0] ^ (int) AesRcon[4*(row/Nk)+0] );  
            temp[1] = (byte)( (int)tmpSubWord[1] ^ (int) AesRcon[4*(row/Nk)+1] );  
            temp[2] = (byte)( (int)tmpSubWord[2] ^ (int) AesRcon[4*(row/Nk)+2] );  
            temp[3] = (byte)( (int)tmpSubWord[3] ^ (int) AesRcon[4*(row/Nk)+3] );  
        }  
        else if ( Nk > 6 && (row % Nk == 4) )  //这个还没有搞清楚 
        {
            SubWord(temp);
            temp[0]=tmpSubWord[0];
            temp[1]=tmpSubWord[1];
            temp[2]=tmpSubWord[2];
            temp[3]=tmpSubWord[3];
        }

        // w[row] = w[row-Nk] xor temp  
        w[4*row+0] = (byte) ( (int) w[4*(row-Nk)+0] ^ (int)temp[0] );  
        w[4*row+1] = (byte) ( (int) w[4*(row-Nk)+1] ^ (int)temp[1] );  
        w[4*row+2] = (byte) ( (int) w[4*(row-Nk)+2] ^ (int)temp[2] );  
        w[4*row+3] = (byte) ( (int) w[4*(row-Nk)+3] ^ (int)temp[3] );  
    }  // for loop
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//轮密钥加  
void AddRoundKey(int round)  
{  
    int i,j;  //i行 j列           //因为密钥w是一列一列排列的,即 k0 k4 k8 k12  
    for(j=0;j<4;j++)              //                              k1 k5 k9 k13  
    {                              //                              k2 k6 k10k14  
        for(i=0;i<4;i++)          //                              k3 k7 k11k15  
        {                          // 所以i行j列的下标是4*((round*4)+j)+i即16*round+4*j+i  
            State[i][j]=(unsigned char)((int)State[i][j]^(int)w[4*((round*4)+j)+i]);  
        }  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//字节代换函数  
void SubBytes()                              //Page 103  
{  
    int i,j;  
    for(j=0;j<4;j++)
        for(i=0;i<4;i++) 
            State[i][j]=AesSbox[State[i][j]];  
            //因为 16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j] 
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
void ShiftRows()  
{  
    unsigned char temp[4*4];                                        //Page105  
    int i,j;  
    for(j=0;j<4;j++)
        for(i=0;i<4;i++)
            temp[4*i+j]=State[i][j];
    for(i=1;i<4;i++)  
    {  
        for(j=0;j<4;j++)  
        {  
            if(i==1)State[i][j]=temp[4*i+(j+1)%4];                    //第一行左移1位  
            else if(i==2)State[i][j]=temp[4*i+(j+2)%4];                //第二行左移2位  
            else if(i==3)State[i][j]=temp[4*i+(j+3)%4];                //第三行左移3位  
        }  
    }  

}  
////////////////////////////////////////////////////////////////////////////////////////////////  
unsigned char gfmultby01(unsigned char b)  
{  
    return b;  
}  
unsigned char gfmultby02(unsigned char b)  
{  
    if (b < 0x80)  
        return (unsigned char)(int)(b <<1);  
    else  
        return (unsigned char)( (int)(b << 1) ^ (int)(0x1b) );  
}  

unsigned char gfmultby03(unsigned char b)  
{  
    return (unsigned char) ( (int)gfmultby02(b) ^ (int)b );  
}  

unsigned char gfmultby09(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^ (int)b );  
}  

unsigned char gfmultby0b(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(b) ^ (int)b );  
}  

unsigned char gfmultby0d(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(gfmultby02(b)) ^ (int)(b) );  
}  

unsigned char gfmultby0e(unsigned char b)  
{  
    return (unsigned char)( (int)gfmultby02(gfmultby02(gfmultby02(b))) ^  
        (int)gfmultby02(gfmultby02(b)) ^(int)gfmultby02(b) );  
} 
////////////////////////////////////////////////////////////////////////////////////////////////  
void MixColumns()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for(j=0;j<4;j++)                                    //2 3 1 1  列混淆矩阵  Page107  
    {                                                    //1 2 3 1  
        for(i=0;i<4;i++)                                //1 1 2 3  
        {                                                //3 1 1 2  
            temp[4*i+j]=State[i][j];  
        }  
    }  
    for(j=0;j<4;j++)  
    {  
        State[0][j] = (unsigned char) ( (int)gfmultby02(temp[0+j]) ^ (int)gfmultby03(temp[4*1+j]) ^  
            (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );  
        State[1][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby02(temp[4*1+j]) ^  
            (int)gfmultby03(temp[4*2+j]) ^ (int)gfmultby01(temp[4*3+j]) );  
        State[2][j] = (unsigned char) ( (int)gfmultby01(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^  
            (int)gfmultby02(temp[4*2+j]) ^ (int)gfmultby03(temp[4*3+j]) );  
        State[3][j] = (unsigned char) ( (int)gfmultby03(temp[0+j]) ^ (int)gfmultby01(temp[4*1+j]) ^  
            (int)gfmultby01(temp[4*2+j]) ^ (int)gfmultby02(temp[4*3+j]) );  
    }  

}
void InvShiftRows()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for(j=0;j<4;j++)
        for(i=0;i<4;i++)
            temp[4*i+j]=State[i][j];
    for(i=1;i<4;i++)  
    {  
        for(j=0;j<4;j++)  
        {  
            //if(i==1)State[i][j]=temp[4*i+(j-1)%4];    在此犯了一个错误 -1%4=-1 而不是3,所以采用了下面再加一个4的做法  
            if(i==1)State[i][j]=temp[4*i+(j+3)%4];            //第一行右移1位 j-1+4=j+3  
            else if(i==2)State[i][j]=temp[4*i+(j+2)%4];        //第二行右移2位 j-2+4=j+2  
            else if(i==3)State[i][j]=temp[4*i+(j+1)%4];        //第三行右移3位 j-3+4=j+2  
        }  
    }  
}  
void InvSubBytes()  
{  
    int i,j;  
    for(j=0;j<4;j++) 
        for(i=0;i<4;i++)
            State[i][j]=AesiSbox[State[i][j]]; //因为 16*(State[i][j]>>4)+State[i][j]&0x0f=State[i][j]  
}  
void InvMixColumns()  
{  
    unsigned char temp[4*4];  
    int i,j;  
    for (i = 0; i < 4; i++)  // copy State into temp[]  
    {  
        for (j = 0; j < 4; j++)                         //0e 0b 0d 09   逆变换矩阵 Page108  
        {                                                //09 0e 0b 0d  
            temp[4*i+j] =  State[i][j];                    //0d 09 0e 0b  
        }                                                //0b 0d 09 0e  
    }  

    for (j = 0; j < 4; j++)  
    {  
        State[0][j] = (unsigned char) ( (int)gfmultby0e(temp[j]) ^ (int)gfmultby0b(temp[4+j]) ^  
            (int)gfmultby0d(temp[4*2+j]) ^ (int)gfmultby09(temp[4*3+j]) );  
        State[1][j] = (unsigned char) ( (int)gfmultby09(temp[j]) ^ (int)gfmultby0e(temp[4+j]) ^  
            (int)gfmultby0b(temp[4*2+j]) ^ (int)gfmultby0d(temp[4*3+j]) );  
        State[2][j] = (unsigned char) ( (int)gfmultby0d(temp[j]) ^ (int)gfmultby09(temp[4+j]) ^  
            (int)gfmultby0e(temp[4*2+j]) ^ (int)gfmultby0b(temp[4*3+j]) );  
        State[3][j] = (unsigned char) ( (int)gfmultby0b(temp[j]) ^ (int)gfmultby0d(temp[4+j]) ^  
            (int)gfmultby09(temp[4*2+j]) ^ (int)gfmultby0e(temp[4*3+j]) );  
    }  
}  
////////////////////////////////////////////////////////////////////////////////////////////////  
//Aes解密函数  
void InvCipher(unsigned char* input,unsigned char* output)  
{  
    int i;  
    memset(&State[0][0],0,16);  
    for (i = 0; i < (4 * Nb); i++)
        State[i % 4][ i / 4] = input[i];

    AddRoundKey(Nr);  

    for (int round = Nr-1; round >= 1; round--)  // main round loop  
    {  
        InvShiftRows();  
        InvSubBytes();  
        AddRoundKey(round);  
        InvMixColumns();  
    }  // end main round loop for InvCipher  

    InvShiftRows();  
    InvSubBytes();  
    AddRoundKey(0);  

    // output = state  
    for (i = 0; i < (4 * Nb); i++)
        output[i] =  State[i % 4][ i / 4];
}  

void inv_aes_deal(int idx,char c)
{
    srcBytes[15]=c;
    memcpy(szLast16Bits,srcBytes,16);
    InvCipher((unsigned char*)szLast16Bits,(unsigned char*)szPlaintextInBytes);
    for(int ii=0;ii<16;ii++)
        decompress_adpter(szPlaintextInBytes[ii]);
}

void inv_aes_store(int idx,char c)
{
    srcBytes[idx]=c;
}

void (*inv_aes_func[])(int idx,char c)={
    inv_aes_store,inv_aes_deal
};

void inv_aes_adpter(char c)
{
    int idx=(count++)%16;
    inv_aes_func[count%16==0](idx,c);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    int nRetCode = 0;

    // initialize MFC and print and error on failure
    if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
    {
        // TODO: change error code to suit your needs
        cerr << _T("Fatal Error: MFC initialization failed") << endl;
        nRetCode = 1;
    }
    else
    {
        if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) //CF_UNICODETEXT
        {
            HGLOBAL hMem = GetClipboardData(CF_TEXT); 
            if (hMem != NULL) 
            {
                LPTSTR lpStr = (LPTSTR)GlobalLock(hMem); 
                if (lpStr != NULL)
                    GlobalUnlock(hMem);
                //解密操作  
                unsigned char* keyBytes=(unsigned char*)"12345678123456781234567812345678"; 
                SetNbNkNr(32);                         //设置密钥块数,轮数  
                memcpy(key,keyBytes,32);                //字符串拷贝函数,把keyBytes的keysize个字符复制到key中  
                KeyExpansion();                                //密钥扩展,必须提前做的初始化  
                TCHAR* Data=lpStr;
                int DataByte=strlen(lpStr);
                m_dictionary= new CPtrArray;
                //解码表
                TCHAR DecodeTable[] =
                {
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                        62, // '+'
                        0, 0, 0,
                        63, // '/'
                        52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
                        0, 0, 0, 0, 0, 0, 0,
                        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
                        0, 0, 0, 0, 0, 0,
                        26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
                        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
                };
                int nValue;
                int i= 0;
                while (i < DataByte)
                {
                    if (*Data != '\r' && *Data!='\n')
                    {
                        nValue = DecodeTable[*Data++] << 18;
                        nValue += DecodeTable[*Data++] << 12;
                        inv_aes_adpter((nValue & 0x00FF0000) >> 16);
                        if (*Data != '=')
                        {
                            nValue += DecodeTable[*Data++] << 6;
                            inv_aes_adpter((nValue & 0x0000FF00) >> 8);
                            if (*Data != '=')
                            {
                                nValue += DecodeTable[*Data++];
                                inv_aes_adpter(nValue & 0x000000FF);
                            }
                        }
                        i += 4;
                    }
                    else// 回车换行,跳过
                    {
                        Data++;
                        i++;
                    }
                }
                unsigned char szLast16Bits[16] = {0};
                unsigned char _temp16bytes[16] = {0};
                if(count<16)
                {
                    memcpy(_temp16bytes,srcBytes,count);
                    InvCipher(_temp16bytes,szPlaintextInBytes);
                    for(int ii=0;ii<count;ii++)
                        decompress_adpter(szPlaintextInBytes[ii]);
                }
                else if(count>16)
                {
                    int iResidue = count % 16;
                    if(iResidue>0)
                        for(int ii=0;ii<iResidue;ii++)
                            decompress_adpter(srcBytes[ii]);
                }
                for(data=(m_SavedData == 0 && m_TotalBits == 0)?m_MaxCode[m_MaxBits]:m_SavedData >> (32 - m_MaxBits),m_SavedData <<= m_MaxBits,m_TotalBits -= m_MaxBits;
                data != m_MaxCode[m_MaxBits];
                data=(m_SavedData == 0 && m_TotalBits == 0)?m_MaxCode[m_MaxBits]:m_SavedData >> (32 - m_MaxBits),m_SavedData <<= m_MaxBits,m_TotalBits -= m_MaxBits)
                {
                    //  Check if the code exist in the dictionary
                    //  if not
                    //  Check if the code exist in the dictionary
                    //  Returns TRUE if so, and FALSE if not.

                    //  If the code is lower then 256, then the element is a normal
                    //  ASCII character, and as such is considered to be in the
                    //  dictionay.
                    if (data >= 256 && data - 256 >= (unsigned)m_dictionary->GetSize())
                    {
                        //  Get the last used character into the decod buffer
                        decodeString.Add((BYTE)character);
                        //  Decode the existing prefix into a known string of data
                        GetBytesFromCode(m_dictionary,&decodeString, prefix);
                    }
                    else
                    {
                        //  Decode the data into the decode buffer
                        GetBytesFromCode(m_dictionary,&decodeString, data);
                        //  Get the last letter inside the data, as the last used letter
                        character = decodeString.GetAt(decodeString.GetSize() - 1);
                    }

                    //  Go over the decode buffer, from the end to the start,
                    //  and write the information into the destination file
                    counter = decodeString.GetSize();
                    while (counter > 0)
                    {
                        writeData = (BYTE)decodeString.GetAt(--counter);
                        strDecode+=writeData;
                    }

                    //  Clear the decode buffer
                    decodeString.RemoveAll();
                    //  Add the new combination into the dictionary
                    //  Add a dictionary element.
                    //  Since the dictionary should already have all the values
                    //  between 0-255, we start it from 256.
                    dicElement *tmp = new dicElement;

                    tmp->m_Prefix = prefix;
                    tmp->m_Letter = (BYTE)character;

                    m_dictionary->Add(tmp);

                    //  Calculate the new buffer size to read now
                    DWORD value=m_dictionary->GetSize() + 257;
                    //  Check the value of the parameter against the Maximum number possible
                    //  and then returns the counter

                    //  This can also be acheived by right shifting the value until we get 0
                    //  and counting the number of times we doing it.

                    for (BYTE counter = 0; counter < 32; counter++)
                        if (value <= m_MaxCode[counter])
                            break;
                    m_MaxBits = counter;

                    //  Since the minimal number of bits we are using is 9 (256 is the begining of the dictionary), 
                    //  then the minimal number of bits is check to return a 9 in case a lower value will be
                    //  reached in the application
                    if (m_MaxBits < 9)
                        m_MaxBits = 9;              
                    //  Set the new prefix to use
                    prefix = data;
                    delete tmp;
                }
                delete m_dictionary;
                char *pMem;
                hMem = GlobalAlloc( GHND | GMEM_DDESHARE, strDecode.length()+1);
                if(hMem)
                {
                    pMem = (char*)GlobalLock(hMem);
                    strcpy(pMem,strDecode.c_str());
                    GlobalUnlock(hMem);
                    EmptyClipboard();
                    SetClipboardData(CF_TEXT,hMem);
                }
                CloseClipboard();
            }
        }
    }

    return nRetCode;
}

将UPX源码clone到本地Linux机器上后,我们需要修改/src/Makefile中的BUILD_TYPE_DEBUG
:= 0 为BUILD_TYPE_DEBUG = 1
,编译出一个带有符号表的debug版本UPX方便后续的调试。此外,UPX依赖UCL算法库,ZLIB算法库和LZMA算法库。在修改完Makefile返回其根目录下输入make
all进行编译时,编译器会报出如下错误提示:
图片 1

测试文本

测试文本

 

2
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
EG4GQCAGkHQHMCAGUGwGUG0GUG4HQHMC4CAFQGgGUCAGMHIGUGEHQGkG8G4CAGEG4GQCAG0GEGkG
4HQGUG4GEG4GMGUCAG8GYCAEYHIGEG0GUHcG8HIGsCAGUGwGUG0GUG4HQHMCAGkHMCAGMG8HYGUH
IGUGQCAGkG4CACIE0G8GQHUGwGUCADMDoCAFAHIG8GMGUHMHMCAC8CAEMG8G4HQHIG8GwCAE8HcG
4GUHIHMGgGkHACICAG8GYCAHQGgGkHMCAG0GEG4HUGEGwC4CAFQGgGkHMCAGkG4HQHIG8GQHUGMH
QGkG8G4CAHcGkGwGwCAHAHIG8HYGkGQGUCAGkG4GYG8HIG0GEHQGkG8G4CAG8G4CAHQGgGUCAGQG
kGYGYGUHIGUG4HQCAHcGEHkHMCAHQG8CAHYGkGUHcCAHQGgGUCAEYHIGEG0GUHcG8HIGsCAG8G4G
wHkC4A0AoFQGgGUHIGUCAGEHIGUCAGQGkGYGYGUHIGUG4HQCAG8HAHQGkG8G4HMCAGEHYGEGkGwG
EGIGwGUCAGYHIG8G0CAHQGgGUCAG0GUG4HUCAG8G4CAHQGgGUCAGwGUGYHQCAG8GYCAHQGgGUCAH
cGkG4GQG8HcCAGYG8HICAHYGkGUHcGkG4GcCAHQGgGUCAEkG4HQGUHIG4GEGwCAEMG8G4HQHIG8G
wCAEYHIGEG0GUHcG8HIGsCAGUGwGUG0GUG4HQHMDoA0AoFIGkHMGsCAFQHIGUGUHMA0AoFQGgGUC
AFIGkHMGsCAFQHIGUGUHMCAHAHIG8HYGkGQGUCAGECAHYGkHMHUGEGwCAHAGkGMHQHUHIGUCAG8G
YCAHQGgGUCAEkG4HQGUHIG4GEGwCAEMG8G4HQHIG8GwCAGYHIGEG0GUHcG8HIGsCAGYG8HICAHQG
gGUCAHMGUGwGUGMHQGUGQCAGUG4HQGkHQHkCACgHMGUGUCAHMGMHIGUGUG4CAHMGgG8HQCAGkG4C
AG4GUHgHQCAHAGEGcGUCkC4CAFQGgGUCAGEHYGEGkGwGEGIGwGUCAHQHIGUGUHMCAGEHIGUDoA0A
oEEGMHQGkG8G4CAE0GEG4GEGcGUG0GUG4HQA0AoFQGgGUCAEEGMHQGkG8G4CAE0GEG4GEGcGUG0G
UG4HQCAHAGEGcGUCAGMG8G4HQGEGkG4HMCAGkG4GYG8HIG0GEHQGkG8G4CAG8G4CAGEGwGwCAHIG
UGMG8HIGQGUGQCAGkHMHMHUGUHMCAGEG4GQCAHIGUG0GUGQGkGEHQGkG8G4CAHAGwGEG4HMCAGYG
8HICAHQGgGUCAHMGUGwGUGMHQGUGQCAE8HIGcGEG4GkHoGEHQGkG8G4CAFUG4GkHQDoA0AoDMC4D
QCAE8HIGcGEG4GkHoGEHQGkG8G4A0AoFQGgGUCAE8HIGcGEG4GkHoGEHQGkG8G4CAHAGEGcGUCAG
MG8G4HQGEGkG4HMCAGkG4GYG8HIG0GEHQGkG8G4CAG8G4CAFIG8GwGUHMCAGEG4GQCAFUHMGUHIH
MCAGEG4GQCAGMGEG4CAGIGUCAHUHMGUGQCAGIHkCAFIGUGcGkG8G4CAEwG8GMGEGwCAFME8HgCAE
MG8G8HIGQGkG4GEHQG8HIHMCAHQG8CAHYGkGUHcCAHQGgGUCAGEGMGMGUHMHMCAGYG8HICAHQGgG
UGkHICAHUG4GkHQHMA0AoEYHUG4GMHQGkG8G4GEGwCAE8HIGEG4GkHoGEHQGkG8G4C0HQGgGkHMC
AHMGUGMHQGkG8G4CAGkHMCAG4G8HQCAGEGMGMGUHMHMGkGIGwGUCAHQG8CAFUHMGUHIHMC4A0AoE
IHUHMGkG4GUHMHMCAFIG8GwGUHMCAC0CAHAHIG8HYGkGQGUHMCAGkG4GYG8HIG0GEHQGkG8G4CAG
8G4CAHcGgGkGMGgCAHUHMGUHIHMCAGgGEHYGUCAGIGUGUG4CAGEHMHMGkGcG4GUGQCAHQG8CAGUG
EGMGgCAG8GYCAHQGgGUCAEIHUHMGkG4GUHMHMCAFIG8GwGUHMCAGkG4CAEIFcGkHMGUA0AoEYHUG
4GMHQGkG8G4HMCAC0CAHQGgGkHMCAGYHUG4GMHQGkG8G4GEGwGkHQHkCAGkHMCAG4G8HQCAHUHMG
UGQCAGIHkCAFMHkG4GcGUG4HQGEA0AoFAGUHIHMG8G4HMCAC0CAHAHIG8HYGkGQGUHMCAGECAGwG
kHMHQCAG8GYCAGEGwGwCAHUHMGUHIHMCAGEG4GQCAHQGgGUCAEIHUHMGkG4GUHMHMCAFIG8GwGUH
MCAHQGgGUHkCAGgGEHYGUCAGIGUGUG4CAGEHMHMGkGcG4GUGQA0AoDMC4DUCAFIGUHAG8HIHQGkG
4GcA0AoFQGgGUCAFIGUHAG8HIHQGkG4GcCAHAGEGcGUCAGMG8G4HQGEGkG4HMCAGEGwGwCAGEHYG
EGkGwGEGIGwGUCAEIFcGkHMGUCAHIGUHAG8HIHQHMC4CAEYHUGwGwCAGQGUHQGEGkGwHMCAG8GYC
AHQGgGUCAGEHYGEGkGwGEGIGwGUCAFIGUHAG8HIHQHMCAGEHIGUCAHAHIG8HYGkGQGUGQCAGkG4C
AE0G8GQHUGwGUCADgCAG8GYCAHQGgGUCAEkG4HMHQHIHUGMHQGkG8G4CAE0GEG4HUGEGwC4A0AoA
0AoFQGgGUCAEIFcGkHMGUCAHMG8GYHQHcGEHIGUCAGMGEG4CAGIGUCAHUHMGUGQCAHQG8CAHMHUH
AHAG8HIHQCAHQGgGUCADUCAHAGgGEHMGUHMCAGkG4CAHQGgGUCAGYG8GwGwG8HcGkG4GcCAHcGEH
kDoA0AoFAGwGEG4G4GkG4GcCACYCAFMGMG8HAGkG4GcCAC0CAFQG8CAHIGUGMG8HIGQCAHQGgGUC
ACIGkG4CAHMGMG8HAGUCICAHAHIG8GMGUHMHMGUHMCAGEG4GQCAHQGgGUCAHMGMG8HAGUCAGEG4G
QCAHMGMGgGUGQHUGwGkG4GcCAG8GYCAHQGgGUCAHIGUHEHUGkHIGUGQCAHQGUHMHQGkG4GcC4CAE
ECACIEYHIGEG0GUHcG8HIGsCICAGkHMCAGMHIGUGEHQGUGQCAGkG4CAEIFcGkHMGUCAGYG8HICAG
UGEGMGgCAGUGwGUG0GUG4HQCAHQG8CAHIGUGYGwGUGMHQCAHQGgGUCACIEkG4CAFMGMG8HAGUCIC
AGEGMHQGkHYGkHQGkGUHMC4A0AoEQG8GMHUG0GUG4HQGEHQGkG8G4CAC0CAFQG8CAGgG8GwGQCAH
QGgGUCAFAHIG8GMGUHMHMCAGEG4GQCAEMG8G4HQHIG8GwCAEQG8GMHUG0GUG4HQGEHQGkG8G4CAG
EG4GQCAGkGQGUG4HQGkGYGkGUGQCAEsGUHkCAEMG8G4HQHIG8GwHMC4A0AoEQGUHMGkGcG4CACYC
AEUGYGYGUGMHQGkHYGUG4GUHMHMCAC0CAFQG8CAGgG8GwGQCAFcGEGwGsHQGgHIG8HUGcGgCAGQG
8GMHUG0GUG4HQGEHQGkG8G4CAGEG4GQCAHIGUGMG8HIGQCAEkHMHMHUGUCAGEG4GQCACkBlA2gZQ
MgGkDCB0A0gbwNwCADgBsAwgbgOYCADCByA0gcwNIG4DOAgAzAcgN4G0BABQA5AbwMYGUDmBzAQA
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
DYAgA7gbwOQGsBcANAFf/wA=

 

按照提示输入命令 git submodule update –init
–recursive后成功下载安装lzma,再次运行make
all报错提示依赖项UCL未找到:
图片 2

 

 

UCL库最后一次版本更新为1.03,运行命令
wget http://www.oberhumer.com/opensource/ucl/download/ucl-1.03.tar.gz 下载UCL源码,编译安装成功后再次运行make
all,报错提示找不到zlib
图片 3

 

 

wget http://pkgs.fedoraproject.org/re …
/zlib-1.2.11.tar.xz 获取最新版本的zlib库并编译安装成功后再次运行make
all编译,编译器未报错,在/src/下发现编译成功的结果upx.out
图片 4

 

 
这个upx.out保留了符号,可以被IDA识别,方便后续进行调试。

0x02
UPX源码结构

UPX根目录包含以下文件及文件夹
图片 5

 

 

其中,README,LICENSE,THANKS等文件的含义显而易见。在/doc中目前包含了elf-to-mem.txt,filter.txt,loader.txt,Makefile,selinux.txt,upx.pod几项。elf-to-mem.txt说明了解压到内存的原理和条件,filter.txt解释了UPX所采用的压缩算法和filter机制,loader.txt告诉开发者如何自定义loader,selinux.txt介绍了SE
Linux中对内存匿名映像的权限控制给UPX造成的影响。这部分文件适用于想更加深入了解UPX的研究者和开发者们,在此我就不多做介绍了。

我们在这个项目中感兴趣的UPX源码都在文件夹/src中,进入该文件夹后我们可以发现其源码由文件夹/src/stub,/src/filter,/lzma-sdk和一系列*.h,
*.cpp文件构成。其中/src/stub包含了针对不同平台,架构和格式的文件头定义和loader源码,/src/filter是一系列被filter机制和UPX使用的头文件。其余的代码文件主要可以分为负责UPX程序总体的main.cpp,work.cp和packmast.cpp,负责加脱壳类的定义与实现的p_*.h和p_*.cpp,以及其他起到显示,运算等辅助作用的源码文件。我们的分析将会从main.cpp入手,经过work.cpp,最终跳转到对应架构和平台的packer()类中。

0x03 加壳前的准备工作

在上文中我们提到分析将会从main.cpp入手。main.cpp可以视为整个工程的“入口”,当我们在shell中调用UPX时,main.cpp中的代码将对程序进行初始化工作,包括运行环境检测,参数解析和实现对应的跳转。

我们从位于main.cpp末尾的main函数开始入手。可以看到main函数开头的代码进行了位数检查,参数检查,压缩算法库可用性检查和针对windows平台进行文件名转换。从1516行开始的switch结构针对不同的命令cmd跳转至不同的case其中compress和decompress操作直接break,在1549行注释标注的check
options语句块后,1565行出现了一个名为do_files的函数。

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
int __acc_cdecl_main main(int argc, char *argv[])
{
        ......
    /* check options */
    ......
    /* start work */
    set_term(stdout);
    do_files(i,argc,argv);
        ......
    return exit_code;
}

do_files()的实现位于文件work.cpp中。work.cpp非常简练,只有do_one_file(),
unlink_ofile()和do_files()三个函数,而do_files()几乎由for循环和try…catch块构成

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
void do_files(int i, int argc, char *argv[])
{
    ......
    for ( ; i < argc; i++)
    {
        infoHeader();
 
 
        const char *iname = argv;
        char oname[ACC_FN_PATH_MAX+1];
        oname[0] = 0;
 
 
        try {
            do_one_file(iname,oname);
        }......
    }
        ......
}

从for循环和iname的赋值我们可以看出UPX具有操作多个文件的功能,每个文件都会调用do_one_file()进行操作。

继续深入do_one_file(),前面的代码对文件名进行处理,并打开了两个自定义的文件流fi和fo,fi读取待操作的文件,fo根据参数创建一个临时文件或创建一个文件,这个参数就是-o.
随后函数获取了PackMaster类的实例pm并调用其成员函数进行操作,在这里我们关心的是pm.pack(&fo)。这个函数的实现位于packmast.cpp中。

packMaster::pack()非常简单,调用了getPacker()获取一个Packer实例,随后调用Packer的成员函数doPack()进行加壳。跳转到getPacker()发现其调用visitAllPakcers()获取Packer

[AppleScript] 纯文本查看 复制代码

?

1
2
3
4
5
6
7
8
Packer *PackMaster::getPacker(InputFile *f)
{
    Packer *pp = visitAllPackers(try_pack, f, opt, f);
    if (!pp)
        throwUnknownExecutableFormat();
    pp->assertPacker();
    return pp;
}

跳转到函数visitAllPackers()中,我们发现获取对应平台和架构的Packer的方法其实是一个遍历操作,以输入文件流fi和不同的Packer类作为参数传递给函数指针类型参数try_pack,通过函数try_pack()进行判断。

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Packer* PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const options_t *o, void *user)
{
    Packer *p = NULL;
......
    // .exe
......
    // atari
......
// linux kernel
...... 
// linux
    if (!o->o_unix.force_execve)
{
           ......       
       if ((p = func(new PackLinuxElf64amd(f), user)) != NULL)
            return p;
        delete p; p = NULL;
        if ((p = func(new PackLinuxElf32armLe(f), user)) != NULL)
            return p;
        delete p; p = NULL;
        if ((p = func(new PackLinuxElf32armBe(f), user)) != NULL)
            return p;
        delete p; p = NULL;
        ......
        }       
    // psone
......
// .sys and .com
    ......
    // Mach (MacOS X PowerPC)
    ......
    return NULL;
}

当且仅当其返回true,函数不返回空,此时visitAllPackers()的对应if分支被执行,packer被传递回PackMaster::pack()执行Packer::doPack()开始加壳。
跳转到位于同一个源码文件下的函数try_pack()

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static Packer* try_pack(Packer *p, void *user)
{
    if (p == NULL)
        return NULL;
    InputFile *f = (InputFile *) user;
    p->assertPacker();
    try {
        p->initPackHeader();
        f->seek(0,SEEK_SET);
        if (p->canPack())
        {
            if (opt->cmd == CMD_COMPRESS)
                p->updatePackHeader();
            f->seek(0,SEEK_SET);
            return p;
        }
    } catch (const IOException&) {
    } catch (...) {
        delete p;
        throw;
    }
    delete p;
    return NULL;
}

try_pack()调用了Packer类的成员函数assertPacker(),
initPackHeader(), canPack(),
updatePackHeader(),在其中起到关键作用的是canPack().通过查看头文件p_lx_elf.h,p_unix.h和packer.h我们发现PackLinuxElf64amd()位于一条以在packer.h中定义的类Packer为基类的继承链尾端,assertPacker(),
initPackHeader()和updatePackHeader()的实现均位于文件packer.cpp中,其功能依次为断言一些UPX信息,初始化和更新一个用于加壳的类PackHeader实例ph.

0x04 Packer的适配和初始化

通过对上一节的分析我们得知Packer能否适配成功最终取决于每一个具体Packer类的成员函数canPack().我们以常用的Linux
for AMD
64为例,其实现位于p_lx_elf.cpp的PackLinuxElf64amd::canPack()中,而Linux
for x86和Linux for
ARM的实现均位于PackLinuxElf32::canPack()中,从visitAllPackers()的代码中我们也可以看到UPX当前并不支持64位ARM平台。

我们接下来将以Linux for AMD
64为例进行代码分析,并在每一个小节的末尾补充Linux for x86和Linux for
ARM的不同之处。我们从PackLinuxElf64amd::canPack()开始:
PackLinuxElf64amd::canPack()
{
第一部分代码,该部分代码主要是对ELF文件头Ehdr和程序运行所需的基本单位Segment的信息Phdr进行校验。代码读取了文件中长度为Ehdr+14*Phdr大小的内容,首先通过checkEhdr()将Ehdr中的字段与预设值进行比较,确定Phdr数量大于1且偏移值正确,随后对Ehdr的大小和偏移进行判定,判定Phdr数量是否大于14,最后确定第一个具有PT_LOAD属性的segment是否覆盖了整个文件的头部。

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
union {
     unsigned char buf[sizeof(Elf64_Ehdr) + 14*sizeof(Elf64_Phdr)];
     //struct { Elf64_Ehdr ehdr; Elf64_Phdr phdr; } e;
 } u;
 COMPILE_TIME_ASSERT(sizeof(u) <= 1024)
 
 
 fi->readx(u.buf, sizeof(u.buf));
 fi->seek(0, SEEK_SET);
 Elf64_Ehdr const *const ehdr = (Elf64_Ehdr *) u.buf;
 
 
 // now check the ELF header
 if (checkEhdr(ehdr) != 0)
     return false;
 
 
 // additional requirements for linux/elf386
 if (get_te16(&ehdr->e_ehsize) != sizeof(*ehdr)) {
     throwCantPack("invalid Ehdr e_ehsize; try '--force-execve'");
     return false;
 }
 if (e_phoff != sizeof(*ehdr)) {// Phdrs not contiguous with Ehdr
     throwCantPack("non-contiguous Ehdr/Phdr; try '--force-execve'");
     return false;
 }
 
 
 // The first PT_LOAD64 must cover the beginning of the file (0==p_offset).
 Elf64_Phdr const *phdr = phdri;
 for (unsigned j=0; j < e_phnum; ++phdr, ++j) {
     if (j >= 14)
         return false;
     if (phdr->T_LOAD64 == get_te32(&phdr->p_type)) {
         load_va = get_te64(&phdr->p_vaddr);
         upx_uint64_t file_offset = get_te64(&phdr->p_offset);
         if (~page_mask & file_offset) {
             if ((~page_mask & load_va) == file_offset) {
                 throwCantPack("Go-language PT_LOAD: try hemfix.c, or try '--force-execve'");
                 // Fixing it inside upx fails because packExtent() reads original file.
             }
             else {
                 throwCantPack("invalid Phdr p_offset; try '--force-execve'");
             }
             return false;
         }
         exetype = 1;
         break;
     }
 }

第二部分代码,从两段长注释中我们可以看出UPX仅支持对位置无关(PIE)的可执行文件和代码位置无关(PIC)的共享库文件进行加壳处理,然而可执行文件和共享库都(可能)具有ET_DYN属性,理论上没有办法将他们区分开。作者采用了一个巧妙的办法:当文件入口点为

__libc_start_main,__uClibc_main或__uClibc_start_main之一时,说明文件依赖于libc.so.6,该文件为满足PIE的可执行文件。因此该部分通过判定文件是否具有ET_DYN属性,若是则在其重定位表中搜寻以上三个符号,满足则跳转至proceed标号处

 
 

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// We want to compress position-independent executable (gcc -pie)
   // main programs, but compressing a shared library must be avoided
   // because the result is no longer usable.  In theory, there is no way
   // to tell them apart: both are just ET_DYN.  Also in theory,
   // neither the presence nor the absence of any particular symbol name
   // can be used to tell them apart; there are counterexamples.
   // However, we will use the following heuristic suggested by
   // Peter S. Mazinger <[email]ps.m@gmx.net[/email]> September 2005:
   // If a ET_DYN has __libc_start_main as a global undefined symbol,
   // then the file is a position-independent executable main program
   // (that depends on libc.so.6) and is eligible to be compressed.
   // Otherwise (no __libc_start_main as global undefined): skip it.
   // Also allow  __uClibc_main  and  __uClibc_start_main .
 
 
   if (Elf32_Ehdr::ET_DYN==get_te16(&ehdr->e_type)) {
       // The DT_STRTAB has no designated length.  Read the whole file.
       alloc_file_image(file_image, file_size);
       fi->seek(0, SEEK_SET);
       fi->readx(file_image, file_size);
       memcpy(&ehdri, ehdr, sizeof(Elf64_Ehdr));
       phdri= (Elf64_Phdr       *)((size_t)e_phoff + file_image)// do not free() !!
       shdri= (Elf64_Shdr const *)((size_t)e_shoff + file_image)// do not free() !!
 
 
       //sec_strndx = &shdri[ehdr->e_shstrndx];
       //shstrtab = (char const *)(sec_strndx->sh_offset + file_image);
       sec_dynsym = elf_find_section_type(Elf64_Shdr::SHT_DYNSYM);
       if (sec_dynsym)
           sec_dynstr = get_te64(&sec_dynsym->sh_link) + shdri;
 
 
       int j= e_phnum;
       phdr= phdri;
       for (; --j>=0; ++phdr)
       if (Elf64_Phdr:T_DYNAMIC==get_te32(&phdr->p_type)) {
           dynseg= (Elf64_Dyn const *)(get_te64(&phdr->p_offset) + file_image);
           break;
       }
       // elf_find_dynamic() returns 0 if 0==dynseg.
       dynstr=          (char const *)elf_find_dynamic(Elf64_Dyn:T_STRTAB);
       dynsym=     (Elf64_Sym const *)elf_find_dynamic(Elf64_Dyn:T_SYMTAB);
 
 
       // Modified 2009-10-10 to detect a ProgramLinkageTable relocation
       // which references the symbol, because DT_GNU_HASH contains only
       // defined symbols, and there might be no DT_HASH.
 
 
       Elf64_Rela const *
       rela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn:T_RELA);
       Elf64_Rela const *
       jmprela= (Elf64_Rela const *)elf_find_dynamic(Elf64_Dyn:T_JMPREL);
       for (   int sz = elf_unsigned_dynamic(Elf64_Dyn:T_PLTRELSZ);
               0 < sz;
               (sz -= sizeof(Elf64_Rela)), ++jmprela
       ) {
           unsigned const symnum = get_te64(&jmprela->r_info) >> 32;
           char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
           if (0==strcmp(symnam, "__libc_start_main")
           ||  0==strcmp(symnam, "__uClibc_main")
           ||  0==strcmp(symnam, "__uClibc_start_main"))
               goto proceed;
       }
 
 
       // 2016-10-09 DT_JMPREL is no more (binutils-2.26.1)?
       // Check the general case, too.
       for (   int sz = elf_unsigned_dynamic(Elf64_Dyn:T_RELASZ);
               0 < sz;
               (sz -= sizeof(Elf64_Rela)), ++rela
       ) {
           unsigned const symnum = get_te64(&rela->r_info) >> 32;
           char const *const symnam = get_te32(&dynsym[symnum].st_name) + dynstr;
           if (0==strcmp(symnam, "__libc_start_main")
           ||  0==strcmp(symnam, "__uClibc_main")
           ||  0==strcmp(symnam, "__uClibc_start_main"))
               goto proceed;
       }

第三部分代码,该部分针对第二部分的“漏网之鱼”,此时将待处理的文件视为共享库文件。共享库文件需要满足PIC——文件中不包含代码重定位信息节DT_TEXTREL。此外,文件最靠前的可执行节地址(通常为.init节代码)必须在重定位信息之后,因为此时链接器ld-linux必须在.init节之前进行重定位,UPX加壳后会将入口点设置在.init节上,必须避免破坏ld-linux所需的信息。若判定通过,变量xct_off将记录下.init段地址(必然不等于0)并作为后续pack函数中对待操作文件是否为共享库的判定条件。
 
   

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
             // Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
        // If there is an existing DT_INIT, and if everything that the dynamic
        // linker ld-linux needs to perform relocations before calling DT_INIT
        // resides below the first SHT_EXECINSTR Section in one PT_LOAD, then
        // compress from the first executable Section to the end of that PT_LOAD.
        // We must not alter anything that ld-linux might touch before it calls
        // the DT_INIT function.
        //
        // Obviously this hack requires that the linker script put pieces
        // into good positions when building the original shared library,
        // and also requires ld-linux to behave.
 
        if (elf_find_dynamic(Elf64_Dyn:T_INIT)) {
            if (elf_has_dynamic(Elf64_Dyn:T_TEXTREL)) {
                throwCantPack("DT_TEXTREL found; re-compile with -fPIC");
                goto abandon;
            }
            Elf64_Shdr const *shdr = shdri;
            xct_va = ~0ull;
            for (j= e_shnum; --j>=0; ++shdr) {
                if (Elf64_Shdr::SHF_EXECINSTR & get_te32(&shdr->sh_flags)) {
                    xct_va = umin64(xct_va, get_te64(&shdr->sh_addr));
                }
            }
            // Rely on 0==elf_unsigned_dynamic(tag) if no such tag.
            upx_uint64_t const va_gash = elf_unsigned_dynamic(Elf64_Dyn:T_GNU_HASH);
            upx_uint64_t const va_hash = elf_unsigned_dynamic(Elf64_Dyn:T_HASH);
            if (xct_va < va_gash  ||  (0==va_gash && xct_va < va_hash)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_STRTAB)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_SYMTAB)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_REL)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_RELA)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_JMPREL)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_VERDEF)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_VERSYM)
            ||  xct_va < elf_unsigned_dynamic(Elf64_Dyn:T_VERNEEDED) ) {
                throwCantPack("DT_ tag above stub");
                goto abandon;
            }
            for ((shdr= shdri), (j= e_shnum); --j>=0; ++shdr) {
                upx_uint64_t const sh_addr = get_te64(&shdr->sh_addr);
                if ( sh_addr==va_gash
                ||  (sh_addr==va_hash && 0==va_gash) ) {
                    shdr= &shdri[get_te32(&shdr->sh_link)];  // the associated SHT_SYMTAB
                    hatch_off = (char *)&ehdri.e_ident[11] - (char *)&ehdri;
                    break;
                }
            }
            ACC_UNUSED(shdr);
            xct_off = elf_get_offset_from_address(xct_va);
            goto proceed;  // But proper packing depends on checking xct_va.
        }
abandon:
        return false;
proceed: ;
    }

第四部分代码,注释中已经说明其调用的是PackUnix::canPack(),函数实现位于p_unix.cpp中。该函数判断待操作文件是否具有可执行权限,大小是否大于4096,并读取最末尾的一部分数据判定是否加壳。
    // XXX
Theoretically the following test should be first,
    // but
PackUnix::canPack() wants 0!=exetype ?
    if
(!super::canPack())
    
   return false;
   
assert(exetype == 1);

    exetype
= 0;

    // set
options
   
opt->o_unix.blocksize = blocksize = file_size;
    return
true;
}
至此,UPX对Packer的适配检查就结束了。通过适配的Packer将会被返回到doPack()中,通过调用其函数pack()进行加壳。
Linux for
x86和Linux for
ARM版本的PackLinuxElf32::canPack()与前例流程几乎一致。不同的是另一个版本的canPack()在第一部分的末尾额外增加了对PT_NOTE段的长度和偏移检测,并对OS
ABI类型做了额外的检测。

0x05
对加壳函数的拆解分析

UPX对所有运行在其支持的架构上的Linux
ELF文件都使用同一个pack(),该函数的实现位于p_unix.cpp中。pack()将很多具体操作下放到了各个子类分别实现的pack1(),
pack2(), pack3(),
pack4()函数中,因此其本体源码并不是很长。通过pack()中的注释我们可以发现其加壳流程大致分为初始化文件头,压缩文件本体,添加loader和修补ELF格式四部分。下面我们以pack1()至pack4()四个函数为分界线进行分析。

(1)对pack1()的分析

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
void PackUnix::pack(OutputFile *fo)
{
......
    // set options
......
    // init compression buffers
......
    fi->seek(0, SEEK_SET);
    pack1(fo, ft)// generate Elf header, etc.
......

位于pack()开头的这部分代码完成的主要工作为初始化了一些和加壳相关的变量,设置了区块大小并在I/O流中分配内存用于加壳,随后调用了pack1()。对于AMD
64来说其实现位于p_lx_elf.cpp中的PackLinuxElf64::pack1()中。

[AppleScript] 纯文本查看 复制代码

?

1
2
3
4
5
6
7
void PackLinuxElf64amd::pack1(OutputFile *fo, Filter &ft)
{
    super::pack1(fo, ft);
    if (0!=xct_off)  // shared library
        return;
    generateElfHdr(fo, stub_amd64_linux_elf_fold, getbrk(phdri, e_phnum) );
}

这个函数调用了父类的同名函数PackLinuxElf64::pack1()进行处理,随后当文件不为共享库时调用PackLinuxElf64::generateElfHdr()生成一个ELF头,所有的代码都位于文件p_lx_elf.cpp中。
首先分析PackLinuxElf64::pack1(),函数的前半部分读取了ELF头部Ehdr和程序运行时所需的信息Phdr,将标志为PT_NOTE的段保存下来(虽然好像并没有用到),计算了PT_LOAD段的page_size和page_mask。当文件为共享库时,根据前面canPack()处的说明,为了保证信息不被修改,xct_off前面的所有数据被原封不动写到输出文件中,此外写入了一个描述loader的结构体l_info

[AppleScript] 纯文本查看 复制代码

?

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
{
    ......
    page_size =  1<<lg2_page;
    page_mask = ~0ull<<lg2_page;
 
 
    progid = 0// getRandomId()not useful, so do not clutter
    if (0!=xct_off) {  // shared library
        fi->seek(0, SEEK_SET);
        fi->readx(ibuf, xct_off);
 
 
        sz_elf_hdrs = xct_off;
        fo->write(ibuf, xct_off);
        memset(&linfo, 0, sizeof(linfo));
        fo->write(&linfo, sizeof(linfo));
}
......

l_info结构体的定义位于/src/stub/src/include/linux.h中

[AppleScript] 纯文本查看 复制代码

?

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图