通过逆向学习软件设计(5)【完结篇】

本篇为完结篇,通过对CRadio的分析拆解,重点完成了对于整个软件中最有价值的电台数据文件的解密,同时作为完结篇也对整个软件另外一个重要的部分——播放的实现做一个连带的梳理,阐述其播放是如何实现的,涉及到的重点就是根据播放源的URL如何进行交换获取数据播放出来;
提纲如下:
- CRadio电台数重点内容据的解密
- 如何应对不同源的请求、交互、播放
- 总结

一、CRadio电台数重点内容据的解密:
接着之前分析的情况,一共六个函数需要处理,第四篇大致说明了其中的一个函数step1_function的处理过程,接下来对后续的函数进行一一说明:
5-1关键函数的调用层次图
接下来对函数step2_function进行分析,该函数中含有三个小函数,这些函数在进行解密过程的方法其实大同小异,关键点上还是要说密码表,只不过不同函数使用的表的大小不一而已,其中,step2_function_1使用的密码如下:

unsigned char arrTable[192] = {
        0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
        0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 
        0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
        0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 
        0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 
        0x0D, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 
        0x0F, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 
        0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 
        0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 
        0x17, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 
        0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 
        0x1D, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };

算法上与step1_function一致,没有什么特别;step2_functon_2所使用的密码表如下:

    unsigned char arrTableData[] = {
        0x0E,0x04,0x0D,0x01,0x02,0x0F,0x0B,0x08,0x03,0x0A,0x06,0x0C,0x05,0x09,0x00,0x07,
        0x00,0x0F,0x07,0x04,0x0E,0x02,0x0D,0x01,0x0A,0x06,0x0C,0x0B,0x09,0x05,0x03,0x08,
        0x04,0x01,0x0E,0x08,0x0D,0x06,0x02,0x0B,0x0F,0x0C,0x09,0x07,0x03,0x0A,0x05,0x00,
        0x0F,0x0C,0x08,0x02,0x04,0x09,0x01,0x07,0x05,0x0B,0x03,0x0E,0x0A,0x00,0x06,0x0D,
        0x0F,0x01,0x08,0x0E,0x06,0x0B,0x03,0x04,0x09,0x07,0x02,0x0D,0x0C,0x00,0x05,0x0A,
        0x03,0x0D,0x04,0x07,0x0F,0x02,0x08,0x0E,0x0C,0x00,0x01,0x0A,0x06,0x09,0x0B,0x05,
        0x00,0x0E,0x07,0x0B,0x0A,0x04,0x0D,0x01,0x05,0x08,0x0C,0x06,0x09,0x03,0x02,0x0F,
        0x0D,0x08,0x0A,0x01,0x03,0x0F,0x04,0x02,0x0B,0x06,0x07,0x0C,0x00,0x05,0x0E,0x09,
        0x0A,0x00,0x09,0x0E,0x06,0x03,0x0F,0x05,0x01,0x0D,0x0C,0x07,0x0B,0x04,0x02,0x08,
        0x0D,0x07,0x00,0x09,0x03,0x04,0x06,0x0A,0x02,0x08,0x05,0x0E,0x0C,0x0B,0x0F,0x01,
        0x0D,0x06,0x04,0x09,0x08,0x0F,0x03,0x00,0x0B,0x01,0x02,0x0C,0x05,0x0A,0x0E,0x07,
        0x01,0x0A,0x0D,0x00,0x06,0x09,0x08,0x07,0x04,0x0F,0x0E,0x03,0x0B,0x05,0x02,0x0C,
        0x07,0x0D,0x0E,0x03,0x00,0x06,0x09,0x0A,0x01,0x02,0x08,0x05,0x0B,0x0C,0x04,0x0F,
        0x0D,0x08,0x0B,0x05,0x06,0x0F,0x00,0x03,0x04,0x07,0x02,0x0C,0x01,0x0A,0x0E,0x09,
        0x0A,0x06,0x09,0x00,0x0C,0x0B,0x07,0x0D,0x0F,0x01,0x03,0x0E,0x05,0x02,0x08,0x04,
        0x03,0x0F,0x00,0x06,0x0A,0x01,0x0D,0x08,0x09,0x04,0x05,0x0B,0x0C,0x07,0x02,0x0E,
        0x02,0x0C,0x04,0x01,0x07,0x0A,0x0B,0x06,0x08,0x05,0x03,0x0F,0x0D,0x00,0x0E,0x09,
        0x0E,0x0B,0x02,0x0C,0x04,0x07,0x0D,0x01,0x05,0x00,0x0F,0x0A,0x03,0x09,0x08,0x06,
        0x04,0x02,0x01,0x0B,0x0A,0x0D,0x07,0x08,0x0F,0x09,0x0C,0x05,0x06,0x03,0x00,0x0E,
        0x0B,0x08,0x0C,0x07,0x01,0x0E,0x02,0x0D,0x06,0x0F,0x00,0x09,0x0A,0x04,0x05,0x03,
        0x0C,0x01,0x0A,0x0F,0x09,0x02,0x06,0x08,0x00,0x0D,0x03,0x04,0x0E,0x07,0x05,0x0B,
        0x0A,0x0F,0x04,0x02,0x07,0x0C,0x09,0x05,0x06,0x01,0x0D,0x0E,0x00,0x0B,0x03,0x08,
        0x09,0x0E,0x0F,0x05,0x02,0x08,0x0C,0x03,0x07,0x00,0x04,0x0A,0x01,0x0D,0x0B,0x06,
        0x04,0x03,0x02,0x0C,0x09,0x05,0x0F,0x0A,0x0B,0x0E,0x01,0x07,0x06,0x00,0x08,0x0D,
        0x04,0x0B,0x02,0x0E,0x0F,0x00,0x08,0x0D,0x03,0x0C,0x09,0x07,0x05,0x0A,0x06,0x01,
        0x0D,0x00,0x0B,0x07,0x04,0x09,0x01,0x0A,0x0E,0x03,0x05,0x0C,0x02,0x0F,0x08,0x06,
        0x01,0x04,0x0B,0x0D,0x0C,0x03,0x07,0x0E,0x0A,0x0F,0x06,0x08,0x00,0x05,0x09,0x02,
        0x06,0x0B,0x0D,0x08,0x01,0x04,0x0A,0x07,0x09,0x05,0x00,0x0F,0x0E,0x02,0x03,0x0C,
        0x0D,0x02,0x08,0x04,0x06,0x0F,0x0B,0x01,0x0A,0x09,0x03,0x0E,0x05,0x00,0x0C,0x07,
        0x01,0x0F,0x0D,0x08,0x0A,0x03,0x07,0x04,0x0C,0x05,0x06,0x0B,0x00,0x0E,0x09,0x02,
        0x07,0x0B,0x04,0x01,0x09,0x0C,0x0E,0x02,0x00,0x06,0x0A,0x0D,0x0F,0x03,0x05,0x08,
        0x02,0x01,0x0E,0x07,0x04,0x0A,0x08,0x0D,0x0F,0x0C,0x09,0x00,0x03,0x05,0x06,0x0B
    };

处理方法也极其简单,贴代码如下:

    char *pResult = arrTableData;
    pResult += (nCount<<6) + (16*(cValue&1))|((cValue&0x1E)>>1)|cValue&0x20;
    return *pResult & 0xF;

step2_function_3函数的处理方法与step1_function、step2_function_1一致,密码表如下:

    unsigned char arrTableData[] = {
        0x0F,0x06,0x13,0x14,0x1C,0x0B,0x1B,0x10,0x00,0x0E,0x16,0x19,0x04,0x11,0x1E,0x09,
        0x01,0x07,0x17,0x0D,0x1F,0x1A,0x02,0x08,0x12,0x0C,0x1D,0x05,0x15,0x0A,0x03,0x18
    };

将step2_function里面的小函数串起来代码如下,其中作者也比较有意思,在做解密过程中,还利用了shagua“傻瓜”这个拼音效果,不知是否在有意嘲讽。。

char* step2_Function( char* pPreparedKey, char* pEncryptData, char pProcessdDataOUT[4] )
{
    if ( NULL == pProcessdDataOUT || NULL == pEncryptData || NULL == pProcessdDataOUT )
        return NULL;

    char arrOUT[6] = { 0 };
    step2_Function__1( pEncryptData, arrOUT );

    //傻瓜.
    char szShagua[] = "shagua";

    unsigned char *pOUT_1 = (unsigned char*)arrOUT;
    unsigned int nCounter_1 = 0;
    do 
    {
        pOUT_1[nCounter_1] ^= (unsigned char)szShagua[nCounter_1] ^ (unsigned char)pPreparedKey[nCounter_1];
    } while ( 6 != ++nCounter_1 );

    unsigned char arrDataProcess[8] = { 0 };
    arrDataProcess[0] = pOUT_1[0] >> 2;
    arrDataProcess[1] = ((pOUT_1[0]&3)<<4) | (pOUT_1[1]>>4);
    arrDataProcess[2] = ((pOUT_1[1]&0xF)*4) | (pOUT_1[2]>>6);
    arrDataProcess[3] = pOUT_1[2]&0x3F;
    arrDataProcess[4] = (pOUT_1[3]>>2)^0x1B;
    arrDataProcess[5] = (pOUT_1[4]>>4) | ((pOUT_1[3]&3)<<4);
    arrDataProcess[6] = (pOUT_1[5]>>6) | ((pOUT_1[4]&0xF)*4);
    arrDataProcess[7] = pOUT_1[5]&0x3F;

    unsigned int nCounter_2 = 0;
    do 
    {
        arrDataProcess[nCounter_2] = step2_Function__2( nCounter_2, arrDataProcess[nCounter_2] );
        ++nCounter_2;
    } while ( 8 != nCounter_2 );

    unsigned int nCounter_3 = 0;
    unsigned int nIdx = 0;
    do 
    {
        unsigned char cVal = arrDataProcess[nIdx] << 4;
        cVal |= arrDataProcess[nIdx+1];
        pOUT_1[nCounter_3] = cVal;
        ++nCounter_3;
        nIdx += 2;
    } while ( 4 != nCounter_3 );

    step2_Function__3( (char*)pOUT_1, (char*)arrDataProcess );

    unsigned int nCounter_4 = 0;
    do 
    {
        pProcessdDataOUT[nCounter_4] = pOUT_1[nCounter_4] ^ 0x1B;
        ++nCounter_4;
    } while ( 4 != nCounter_4 );

    return pProcessdDataOUT;

step3_function的算法与之前的如出一辙,也只是密码表的不同而已,逆向等价代码如下:

char* step3_Function( char *pINOUTData )
{
    if ( NULL == pINOUTData )
        return NULL;

    char arrData[8] = { 0 };
    int nIdx = 0;
    //Data Table
    unsigned char arrDataTable[64] = {
        0x27, 0x07, 0x2F, 0x0F, 0x37, 0x17, 0x3F, 0x1F, 0x26, 0x06, 0x2E, 0x0E, 0x36, 0x16, 0x3E, 0x1E, 
        0x25, 0x05, 0x2D, 0x0D, 0x35, 0x15, 0x3D, 0x1D, 0x24, 0x04, 0x2C, 0x0C, 0x34, 0x14, 0x3C, 0x1C, 
        0x23, 0x03, 0x2B, 0x0B, 0x33, 0x13, 0x3B, 0x1B, 0x22, 0x02, 0x2A, 0x0A, 0x32, 0x12, 0x3A, 0x1A, 
        0x21, 0x01, 0x29, 0x09, 0x31, 0x11, 0x39, 0x19, 0x20, 0x00, 0x28, 0x08, 0x30, 0x10, 0x38, 0x18
    };
    char *pDataTable = (char*)arrDataTable;
    do
    {
        char cVal_1 = *(pINOUTData+ ((unsigned int)(*(unsigned char*)pDataTable) >> 3));
        char cVal_2 = 1 << (7-((*pDataTable) & 7));
        if ( cVal_1 & cVal_2 )
            arrData[nIdx>>3] |= 1 << (7-(nIdx&7));
        ++nIdx;
        ++pDataTable;
    } while ( 64 != nIdx );

    int nCount = 8;
    char *pData = arrData;
    do 
    {
        *pINOUTData++ = *pData++;
        --nCount;
    } while ( 0 != nCount );
//    return (pINOUTData-8); in order to print out the result
    return pINOUTData;
}

最后整合这些代码到关键函数,获取到:

bool decode8BytesEncryptData(
IN     char pArrEncryptData[8],
OUT    char pArrDecodeResult[8] )
{
    if ( NULL == pArrDecodeResult || NULL == pArrDecodeResult )
        return false;

    //First copy the encryptData ignore that process
    ZeroMemory( pArrDecodeResult, 8 );

    step1_Function( (char*)pArrEncryptData+4, pArrDecodeResult );


    //!!!Notice:PrepareKey function is ignored at this moment.
    //Here is the Prepared_Key as below
    //unsigned AnsiChar data[] = {
    //    0x5E, 0x7F, 0xFB, 0xE5, 0xE2, 0x87, 0x7F, 0xCB, 0xF5, 0x23, 0xAB, 0x89, 
    //    0x9F, 0xF9, 0xBF, 0x72, 0x35, 0x17, 0xBF, 0x27, 0xFF, 0x6F, 0x01, 0xAE, 0xFF, 0x5E, 0xAD, 0x44, 
    //    0x79, 0xCB, 0xDB, 0xBB, 0xFC, 0x66, 0x90, 0x7D, 0x9C, 0xFE, 0xFF, 0xC3, 0x9D, 0xEA, 0xF7, 0x7F, 
    //    0x6E, 0x0C, 0x9F, 0x39, 0x76, 0xBF, 0xBF, 0xBC, 0x54, 0x68, 0xFF, 0xB4, 0x77, 0xC8, 0xDA, 0x66, 
    //    0xEF, 0xCE, 0xFE, 0x94, 0xEE, 0xB8, 0xFE, 0xF3, 0xBE, 0xB9, 0x1E, 0x51, 0xBE, 0x9F, 0x7B, 0x9B, 
    //    0xE2, 0x32, 0xEF, 0x7A, 0x7F, 0x35, 0x6F, 0x04, 0xAF, 0xFF, 0xDC, 0xB8, 0x20, 0xD6, 0xF7, 0x55, 
    //    0xDF, 0xD3, 0x21, 0xF5 };
    unsigned char arrPreparedKey[6*16] = { 0x5E, 0x7F, 0xFB, 0xE5, 0xE2, 0x87, 0x7F, 0xCB, 0xF5, 0x23, 0xAB, 0x89, \
        0x9F, 0xF9, 0xBF, 0x72, 0x35, 0x17, 0xBF, 0x27, 0xFF, 0x6F, 0x01, 0xAE, 0xFF, 0x5E, 0xAD, 0x44,   \
        0x79, 0xCB, 0xDB, 0xBB, 0xFC, 0x66, 0x90, 0x7D, 0x9C, 0xFE, 0xFF, 0xC3, 0x9D, 0xEA, 0xF7, 0x7F,   \
        0x6E, 0x0C, 0x9F, 0x39, 0x76, 0xBF, 0xBF, 0xBC, 0x54, 0x68, 0xFF, 0xB4, 0x77, 0xC8, 0xDA, 0x66,   \
        0xEF, 0xCE, 0xFE, 0x94, 0xEE, 0xB8, 0xFE, 0xF3, 0xBE, 0xB9, 0x1E, 0x51, 0xBE, 0x9F, 0x7B, 0x9B,   \
        0xE2, 0x32, 0xEF, 0x7A, 0x7F, 0x35, 0x6F, 0x04, 0xAF, 0xFF, 0xDC, 0xB8, 0x20, 0xD6, 0xF7, 0x55,   \
        0xDF, 0xD3, 0x21, 0xF5 };

    char arrFirst4Bytes[4] = { 0 };
    unsigned int nCounter = 0;
    do 
    {
        memcpy( arrFirst4Bytes, pArrDecodeResult, 4 );
        memcpy( pArrDecodeResult, pArrDecodeResult+4, 4 );
        char arrOUT_Step2[4] = { 0 };
        step2_Function( (char*)arrPreparedKey+90-nCounter*6, pArrDecodeResult, arrOUT_Step2 );
        unsigned int nIdx = 0;
        char *pDecode = (char*)pArrDecodeResult + 4;
        do 
        {
            *(pDecode+nIdx) = arrOUT_Step2[nIdx] ^ arrFirst4Bytes[nIdx];
        } while ( 4 != ++nIdx );

        ++nCounter;
    } while ( 16 != nCounter );

    memcpy( arrFirst4Bytes, (char*)pArrDecodeResult+4, 4 );
    memcpy( pArrDecodeResult+4, (char*)pArrDecodeResult, 4 );
    memcpy( (char*)pArrDecodeResult, arrFirst4Bytes, 4 );

    step3_Function( pArrDecodeResult );

    return true;
}

这其中有个很重要的步骤就是计算出Prepared_Key这个过程的分析及生成过程我省略了,有兴趣的童鞋可以自行研究,也是专门的函数处理的,算法不难,无非也是一些位的计算处理,各种异或而已,为了大家研究方便我就贴出汇编代码的截图吧:
关于PreparedKey的生成函数
最后根据以上,结合之前几篇的内容,自制一个简单的根据ID来获取电台URL的程序就完成了,其中还要强调一点的是对于解密数据的处理,这里面有个超过三位的问题,需要移一个字节,这个地方必须处理好,不然在超过三位的情况就解密不出来了。
效果图如下:
解密三位以内的效果
四位的解密效果
以上对于电台加密URL的最重要的一个过程就是对程序最小单位——函数的一一验证过程,根据构造的Input与正确的Output进行对比来进行简单地验证以确初步保函数的正确性;
验证代码如下:

#if 0
    //Key
    unsigned char arrKey[8] = { 0xBB, 0x82, 0xE7, 0xD6, 0xB6, 0xF1, 0xFB, 0x75 };         //8Bytes

    //!!!Notice:PrepareKey function is ignored at this moment.
    //Here is the Prepared_Key as below
    //unsigned AnsiChar data[] = {
    //    0x5E, 0x7F, 0xFB, 0xE5, 0xE2, 0x87, 0x7F, 0xCB, 0xF5, 0x23, 0xAB, 0x89, 
    //    0x9F, 0xF9, 0xBF, 0x72, 0x35, 0x17, 0xBF, 0x27, 0xFF, 0x6F, 0x01, 0xAE, 0xFF, 0x5E, 0xAD, 0x44, 
    //    0x79, 0xCB, 0xDB, 0xBB, 0xFC, 0x66, 0x90, 0x7D, 0x9C, 0xFE, 0xFF, 0xC3, 0x9D, 0xEA, 0xF7, 0x7F, 
    //    0x6E, 0x0C, 0x9F, 0x39, 0x76, 0xBF, 0xBF, 0xBC, 0x54, 0x68, 0xFF, 0xB4, 0x77, 0xC8, 0xDA, 0x66, 
    //    0xEF, 0xCE, 0xFE, 0x94, 0xEE, 0xB8, 0xFE, 0xF3, 0xBE, 0xB9, 0x1E, 0x51, 0xBE, 0x9F, 0x7B, 0x9B, 
    //    0xE2, 0x32, 0xEF, 0x7A, 0x7F, 0x35, 0x6F, 0x04, 0xAF, 0xFF, 0xDC, 0xB8, 0x20, 0xD6, 0xF7, 0x55, 
    //    0xDF, 0xD3, 0x21, 0xF5 };
    unsigned char arrPreparedKey[6*16] = { 0x5E, 0x7F, 0xFB, 0xE5, 0xE2, 0x87, 0x7F, 0xCB, 0xF5, 0x23, 0xAB, 0x89, 
        0x9F, 0xF9, 0xBF, 0x72, 0x35, 0x17, 0xBF, 0x27, 0xFF, 0x6F, 0x01, 0xAE, 0xFF, 0x5E, 0xAD, 0x44, 
        0x79, 0xCB, 0xDB, 0xBB, 0xFC, 0x66, 0x90, 0x7D, 0x9C, 0xFE, 0xFF, 0xC3, 0x9D, 0xEA, 0xF7, 0x7F, 
        0x6E, 0x0C, 0x9F, 0x39, 0x76, 0xBF, 0xBF, 0xBC, 0x54, 0x68, 0xFF, 0xB4, 0x77, 0xC8, 0xDA, 0x66, 
        0xEF, 0xCE, 0xFE, 0x94, 0xEE, 0xB8, 0xFE, 0xF3, 0xBE, 0xB9, 0x1E, 0x51, 0xBE, 0x9F, 0x7B, 0x9B, 
        0xE2, 0x32, 0xEF, 0x7A, 0x7F, 0x35, 0x6F, 0x04, 0xAF, 0xFF, 0xDC, 0xB8, 0x20, 0xD6, 0xF7, 0x55, 
        0xDF, 0xD3, 0x21, 0xF5 };

    //////////////////////////////////////////////////////////////////////////
    //Test steps
    std::cout << "===========Testing beginning as below===========" << std::endl;
    //////////////////////////////////////////////////////////////////////////
    //Test step1_Function
    char arrDataOUT_1[9] = { 0 };
    //step1_Function( pData+4, arrDataOUT_1 ); //Test passed!
    std::cout << "step1_Function output as below" << std::endl;
    PrintArrayHex(arrDataOUT_1, 8 );
    std::cout << "ASCII value :" << arrDataOUT_1 << std::endl;
    //////////////////////////////////////////////////////////////////////////


    //////////////////////////////////////////////////////////////////////////
    //Test step2_Function__1
    //Test input
    unsigned char arrInputStep2Data_1[] = { 0xBA, 0xAD, 0x4A, 0xA1, 0xBA, 0xAD, 0x4A, 0xA1, 0 };
    char arrDataOUT_2[6+1] = { 0 };
    step2_Function__1( (char*)arrInputStep2Data_1, arrDataOUT_2 );
    PrintArrayHex( arrDataOUT_2, 6 );
    std::cout << "ASCII value :" << arrDataOUT_2 << std::endl;


    //////////////////////////////////////////////////////////////////////////
    //Test step2_Function__2
    char arrInputStep2Data_2[] = { 0x16, 0x36, 0x23, 0x24, 0x1F, 0x10, 0x06, 0x17 };
    unsigned int nCounter = 0;
    do 
    {
        char cVal = step2_Function__2(nCounter, arrInputStep2Data_2[nCounter]);
        std::cout << std::hex << (unsigned short)cVal << " ";
        nCounter++;
    } while ( 8 != nCounter );
    std::cout << std::endl;



    //////////////////////////////////////////////////////////////////////////
    //Test step2_Function__3
    //char arrInputStep2Data_3[] = { };
    unsigned char arrInputStep2Data_3[] = { 0xC6, 0xA9, 0x60, 0xEB };
    char arrDataOUT_3[4+1] = { 0 };
    step2_Function__3( (char*)arrInputStep2Data_3, arrDataOUT_3 );
    PrintArrayHex( arrDataOUT_3, 4 );

    //////////////////////////////////////////////////////////////////////////
    //Test step2_Function
    //
    //Test data
    //pData        = { 0xBA, 0xAD, 0x4A, 0xA1, 0xBA, 0xAD, 0x4A, 0xA1 };
    //pPreparedKey = { 0xF7, 0x55, 0xDF, 0xD3, 0x21, 0xF5 };
    unsigned char arrPreparedKey_Step2[6] = { 0xF7, 0x55, 0xDF, 0xD3, 0x21, 0xF5 };
    unsigned char arrDataFun2[4] = { 0xBA, 0xAD, 0x4A, 0xA1 };
    char arrOUTFun2[4] = { 0 };
    step2_Function( (char*)arrPreparedKey_Step2, (char*)arrDataFun2, arrOUTFun2 );
    std::cout << "step2_Function processed out value as below:" << std::endl;
    PrintArrayHex( arrOUTFun2, 4 );        


    //////////////////////////////////////////////////////////////////////////
    //Test step3_function
    //          encrypt data                                      
    //0012FA18  09 C3 C0 B9 FA 09 09 09                          .美国...
    //F7 01 83 56 00 E8 E2 93....................................VOA Chin
    //char arrData[8+1] = { 0x16, 0x18, 0x00, 0xEB, 0x1E, 0x18, 0xF9, 0x12, 0 };
    unsigned char arrData[8+1] = { 0xF7, 0x01, 0x83, 0x56, 0x00, 0xE8, 0xE2, 0x93, 0 };
    step3_Function( (char*)arrData );
    std::cout << arrData << std::endl; //Test passed!
    //////////////////////////////////////////////////////////////////////////


    //////////////////////////////////////////////////////////////////////////
    //Test decode8BytesEncryptData
    //Testing input data:
    //char arrInputData[] = { 0x32, 0x98, 0x74, 0xA9, 0x84, 0xA7, 0x5D, 0xA7 };
    ////Output Result should be:56 4F 41 20 43 68 69 6E                          VOA Chin
    char arrOUTResult[8+1] = { 0 };
    decode8BytesEncryptData( pData, arrOUTResult );
    PrintArrayHex( arrOUTResult, 8 );
    std::cout << "ASCII value :" << arrOUTResult << std::endl;

    std::cout<< "===========Testing End ==========================" << std::endl;
#endif

二、请求、交互、播放的实现方式:
首先,采用一个最为简单的API监控的方式就可以获取从链接到请求的所有调用流程的方法获取,关键还是利用API的调用来进行,且由于在关键实现过程中,此软件不可避免地用到多处关键的API,因此整个过程变得更加清晰起来,采用API Monitor进行大致流程的梳理是一个很好进行接下来细致梳理探究具体实现的重要前奏。
调用WMSDK
接下来,利用OD结合IDA来分析细致流程(待完成,PS结合WMSDK的lib制作签名文件分析效果更好)


快捷键

  • 加粗 Ctrl + B
  • 斜体 Ctrl + I
  • 引用 Ctrl + Q
  • 插入链接 Ctrl + L
  • 插入代码 Ctrl + K
  • 插入图片 Ctrl + G
  • 提升标题 Ctrl + H
  • 有序列表 Ctrl + O
  • 无序列表 Ctrl + U
  • 横线 Ctrl + R
  • 撤销 Ctrl + Z
  • 重做 Ctrl + Y
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值