您的位置:首页 > 其它

loginEx

2015-11-06 04:17 369 查看
/// @file exam_1_1.c
/** @brief
* 输入用户名和口令, 3次输入错误就退出, 正确输入显示ok.
* 编译后的PE文件在WinHex中看不到明文
* 关键数据使用用户输入信息进行解密
*/

#define _WIN32_WINNT 0x0500
#include <windows.h>

#include <stdlib.h>
#include <stdio.h>
#include <crtdbg.h>
#include <string.h>
#include <time.h>

#ifndef BOOL
#define BOOL int
#define TRUE 1
#define FALSE 0
#endif

// #define DEBUG_FOR_LS ///< 调试标记, 发行时一定要关掉(注释掉)

#define CIPHER_ENC TRUE ///< 加密
#define CIPHER_DEC FALSE ///< 解密

/// 提示信息加固
#ifdef DEBUG_FOR_LS
#define SZ_PLEASE_INPUT_NAME "please input login user name:"
#define SZ_PLEASE_INPUT_PWD "please input login password:"
#define SZ_LOGIN_OK "login ok, entry system...\n"
#define SZ_LOGIN_ERR "error: please try again\n"
#define SZ_CONNECT_ADMIN "sorry, please connect admin, press any key to quit\n"
#define SZ_QUIT "END, press any key to quit\n"
#endif // #ifdef DEBUG_FOR_LS

/// 密文buffer size
#define ARR_SIZE_PLEASE_INPUT_NAME 32
#define ARR_SIZE_PLEASE_INPUT_PWD 32
#define ARR_SIZE_LOGIN_OK 32
#define ARR_SIZE_LOGIN_ERR 32
#define ARR_SIZE_CONNECT_ADMIN 64
#define ARR_SIZE_QUIT 32

#define LEN_USER 5
#define LEN_PWD 9
#define LEN_TOKEN (LEN_USER + LEN_PWD)

// #define SZ_USER "admin"
// #define SZ_PWD "hello_vs6"
#define DW_HASH_USER_AND_PWD 0x0157c000

unsigned char szUser[LEN_USER] = {0}; ///< 用户名存储区
unsigned char szPwd[LEN_PWD] = {0}; ///< 用户口令存储区

/// szToKen的布局 = (szUser + szPwd) 被校验和按字节异或
unsigned char szToKen[LEN_TOKEN] = {0}; ///< 令牌存储区(由szUser和szPwd生成)

unsigned char cNormalPwdTble[] = 
{
    /// 密码表必须为 0~13, 否则char加密后,范围不在 0~127
    /// 密码表做的是减法
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 2, 3, 4, 
    5, 6, 7, 8, 9, 10, 11, 12, 13, 3, 4, 5, 6, 7, 8, 9, 
    10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 5, 6
};

unsigned char szTip_Input_name_org[ARR_SIZE_PLEASE_INPUT_NAME] = 
#ifdef DEBUG_FOR_LS
    SZ_PLEASE_INPUT_NAME;
#else
    {0};
#endif

unsigned char szTip_Input_name_enc[ARR_SIZE_PLEASE_INPUT_NAME] = {
    0x6f, 0x6a, 0x62, 0x5d, 0x6e, 0x5f, 0x19, 0x61,
    0x65, 0x66, 0x6a, 0x68, 0x13, 0x6a, 0x6c, 0x63,
    0x64, 0x68, 0x19, 0x6d, 0x6a, 0x5b, 0x67, 0x14,
    0x61, 0x5e, 0x69, 0x60, 0x34, 0xf9, 0xf8, 0xf7,};

unsigned char szTip_Input_pwd_org[ARR_SIZE_PLEASE_INPUT_PWD] = 
#ifdef DEBUG_FOR_LS
    SZ_PLEASE_INPUT_PWD;
#else
    {0};
#endif

unsigned char szTip_Input_pwd_enc[ARR_SIZE_PLEASE_INPUT_PWD] = {
    0x6f, 0x6a, 0x62, 0x5d, 0x6e, 0x5f, 0x19, 0x61,
    0x65, 0x66, 0x6a, 0x68, 0x13, 0x6a, 0x6c, 0x63,
    0x64, 0x68, 0x19, 0x68, 0x58, 0x69, 0x68, 0x6b,
    0x62, 0x6f, 0x60, 0x35, 0xfa, 0xf9, 0xf8, 0xf7};

unsigned char szTip_login_ok_org[ARR_SIZE_LOGIN_OK] = 
#ifdef DEBUG_FOR_LS
    SZ_LOGIN_OK;
#else
    {0};
#endif

unsigned char szTip_login_ok_enc[ARR_SIZE_LOGIN_OK] = {
    0x0c, 0xcd, 0x2a, 0x05, 0x05, 0xb9, 0xcc, 0x2d,
    0xc3, 0xb6, 0xcc, 0x36, 0x0a, 0x45, 0x79, 0xc0,
    0xd1, 0x3c, 0x0f, 0x0b, 0xfe, 0xca, 0xf0, 0xc5,
    0xc4, 0x71, 0xc8, 0x96, 0xd3, 0x00, 0xa0, 0x5e};

unsigned char szTip_login_err_org[ARR_SIZE_LOGIN_ERR] = 
#ifdef DEBUG_FOR_LS
    SZ_LOGIN_ERR;
#else
    {0};
#endif

unsigned char szTip_login_err_enc[ARR_SIZE_LOGIN_ERR] = {
    0x64, 0x70, 0x6f, 0x6b, 0x6d, 0x34, 0x19, 0x68,
    0x63, 0x5b, 0x56, 0x67, 0x58, 0x1e, 0x71, 0x6e,
    0x74, 0x1a, 0x5a, 0x5f, 0x58, 0x5f, 0x63, 0xfe,
    0xf3, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7};

unsigned char szTip_connect_admin_org[ARR_SIZE_CONNECT_ADMIN] = 
#ifdef DEBUG_FOR_LS
    SZ_CONNECT_ADMIN;
#else
    {0};
#endif

unsigned char szTip_connect_admin_enc[ARR_SIZE_CONNECT_ADMIN] = {
    0x72, 0x6d, 0x6f, 0x6e, 0x74, 0x26, 0x19, 0x68,
    0x63, 0x5b, 0x56, 0x67, 0x58, 0x1e, 0x60, 0x6b,
    0x69, 0x68, 0x5e, 0x5b, 0x6b, 0x16, 0x56, 0x58,
    0x60, 0x66, 0x6a, 0x27, 0x1a, 0x69, 0x6a, 0x5c,
    0x69, 0x68, 0x14, 0x54, 0x6a, 0x74, 0x1a, 0x64,
    0x5d, 0x70, 0x16, 0x69, 0x63, 0x13, 0x6c, 0x6f,
    0xf9, 0x73, 0x08, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9,
    0xf8, 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xfe, 0xfd};

unsigned char szTip_quit_org[ARR_SIZE_QUIT] = 
#ifdef DEBUG_FOR_LS
    SZ_QUIT;
#else
    {0};
#endif

unsigned char szTip_quit_enc[ARR_SIZE_QUIT] = {
    0x44, 0x4c, 0x41, 0x28, 0x1b, 0x6a, 0x6b, 0x5d,
    0x6a, 0x69, 0x15, 0x55, 0x61, 0x77, 0x1d, 0x67,
    0x60, 0x73, 0x19, 0x6c, 0x66, 0x16, 0x66, 0x69,
    0x5c, 0x71, 0x06, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7,};

/// 通用的加解密函数
BOOL fnDataCryptOrDecrypt(
    BOOL bEncrypt, ///< TRUE = 加密, FALSE = 解密
    unsigned char szDataIn[], ///< 数据输入区
    int iSizeDataIn, ///< 数据输入区长度
    unsigned char szDataOut[], ///< 数据输出区
    int iSizeDataOut, ///< 数据输出区长度
    unsigned char szPwdTble[], ///< 密码表
    int iSizePwdTble); ///< 密码表长度

/// 打印加密字符串
void PrintfStringWasEnc(
    unsigned char szDataIn[], ///< 数据输入区
    int iSizeDataIn, ///< 数据输入区长度
    unsigned char szPwdTble[], ///< 密码表
    int iSizePwdTble); ///< 密码表长度

void QuitIsOnDebugger(); ///< 检测到调试器,就直接退了

static void makeEncData(); ///< ***加密数据
static BOOL inputUserInfo(); ///< 输入用户信息
unsigned char int2char(int iIn, int iByteIndex); ///< 从iIn中的0, 1, 2, 3位置取出 char

static int sum_alg_char_array(char ary[], int iLenAry);
static int sum_alg(int ary[], int iLenAry);

int main(int argc, char** argv)
{
    BOOL bRc = FALSE;
    int iRetryCnt = 3;

    srand(time(NULL));

    /// 非关键数据的加解密 用的密钥是 cNormalPwdTble
    /// 关键数据的加密用的是正确的用户口令
    /// 关键数据的解密用的是用户输入的口令

    makeEncData();

    do 
    {
        if (inputUserInfo())
        {
            /// 这里的关键数据是拿token来解密的
            PrintfStringWasEnc(
                szTip_login_ok_enc, 
                sizeof(szTip_login_ok_enc), 
                szToKen, 
                sizeof(szToKen) / sizeof(szToKen[0]));
            bRc = TRUE;
            break;
        }
        else
        {
            if (iRetryCnt > 1)
            {
                PrintfStringWasEnc(
                    szTip_login_err_enc, 
                    sizeof(szTip_login_err_enc), 
                    cNormalPwdTble, 
                    sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));
            }

            if ((rand() % 2) > 0)
            {
                /// 不想每次都固定执行到这里, 容易让人家发现
                QuitIsOnDebugger();
            }
        }
    } while ((--iRetryCnt > 0)); ///< 错误重试次数 = 3

    if (!bRc)
    {
        PrintfStringWasEnc(
            szTip_connect_admin_enc, 
            sizeof(szTip_connect_admin_enc), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));
    }
    else
    {
        PrintfStringWasEnc(
            szTip_quit_enc, 
            sizeof(szTip_quit_enc), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));
    }

    getchar();
    return 0;
}

void PrintfStringWasEnc(
    unsigned char szDataIn[], ///< 数据输入区
    int iSizeDataIn, ///< 数据输入区长度
    unsigned char szPwdTble[], ///< 密码表
    int iSizePwdTble) ///< 密码表长度
{
    char cTmp = '\0';
    int i = 0;
    int iPwdTbleIndex = 0;
    
    do 
    {
        if ((iSizeDataIn <= 0) ///< 对称加解密缓冲区程度相同
            || (iSizePwdTble <= 0)) ///< 密码表长度必须 > 0
        {
            break;
        }

        for (i = 0; i < iSizeDataIn; i++)
        {
            if (iPwdTbleIndex > iSizePwdTble)
            {
                iPwdTbleIndex = 0;
            }

            /// 解密
            cTmp = szDataIn[i] + szPwdTble[iPwdTbleIndex++];
            if (0 != cTmp)
            {
                printf("%c", cTmp);
            }
        }
    } while (0);
}

BOOL fnDataCryptOrDecrypt(
    BOOL bEncrypt, ///< TRUE = 加密, FALSE = 解密
    unsigned char szDataIn[], ///< 数据输入区
    int iSizeDataIn, ///< 数据输入区长度
    unsigned char szDataOut[], ///< 数据输出区
    int iSizeDataOut, ///< 数据输出区长度
    unsigned char szPwdTble[], ///< 密码表
    int iSizePwdTble) ///< 密码表长度
{
    BOOL bRc = FALSE;
    BOOL bNeedCipher = FALSE; ///< 需要密码学操作的标志
    int i = 0;
    int iPwdTbleIndex = 0;
    
    do 
    {
        if ((iSizeDataIn != iSizeDataOut) ///< 对称加解密缓冲区程度相同
            || (iSizePwdTble <= 0)) ///< 密码表长度必须 > 0
        {
            break;
        }

        #ifdef DEBUG_FOR_LS
        printf("\n\n");
        #endif
        
        for (i = 0; i < iSizeDataIn; i++)
        {
            if (iPwdTbleIndex > iSizePwdTble)
            {
                iPwdTbleIndex = 0;
            }

            if (bEncrypt)
            {
                /// 加密
                szDataOut[i] = szDataIn[i] - szPwdTble[iPwdTbleIndex++];

                #ifdef DEBUG_FOR_LS
                printf("0x%02x, ", szDataOut[i]);
                #endif

                if (0 == ((i + 1) % 8))
                {
                    #ifdef DEBUG_FOR_LS
                    printf("\n");
                    #endif
                }
            }
            else
            {
                /// 解密
                szDataOut[i] = szDataIn[i] + szPwdTble[iPwdTbleIndex++];
            }
        }

        #ifdef DEBUG_FOR_LS
        printf("\n\n");
        #endif

        bRc = TRUE;
    } while (0);

    return bRc;
}

void QuitIsOnDebugger()
{
    if (IsDebuggerPresent())
    {
        exit(0);
    }
}

static BOOL inputUserInfo()
{
    BOOL bRc = FALSE;
    unsigned char cTmp = '\0';
    int i = 0;
    int iSum = 0;

    do 
    {
        /// ----------------------------------------
        /// 输入用户名
        /// ----------------------------------------
        PrintfStringWasEnc(
            szTip_Input_name_enc, 
            sizeof(szTip_Input_name_enc), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

        i = 0;
        do 
        {
            cTmp = getchar();
            if (i < LEN_USER)
            {
                szUser[i] = cTmp;   
            }

            i++;
        } while ('\n' != cTmp);

        /// 将用户名转成密文, 不管对错, 只是为了让反方看不到明文
        fnDataCryptOrDecrypt(
            CIPHER_ENC, 
            szUser, 
            sizeof(szUser), 
            szUser, 
            sizeof(szUser), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

        /// 最后还有一个回车
        if (i > (LEN_USER + 1))
        {
            break;
        }

        /// ----------------------------------------
        /// 输入用户口令
        /// ----------------------------------------
        PrintfStringWasEnc(
            szTip_Input_pwd_enc, 
            sizeof(szTip_Input_pwd_enc), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

        i = 0;
        do 
        {
            cTmp = getchar();
            if (i < LEN_PWD)
            {
                szPwd[i] = cTmp;   
            }

            i++;
        } while ('\n' != cTmp);

        /// 将用户口令转成密文, 不管对错, 只是为了让反方看不到明文
        fnDataCryptOrDecrypt(
            CIPHER_ENC, 
            szPwd, 
            sizeof(szPwd), 
            szPwd, 
            sizeof(szPwd), 
            cNormalPwdTble, 
            sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

        /// 最后还有一个回车
        if (i > (LEN_PWD + 1))
        {
            break;
        }

        /// 算出用户名和口令的校验和
        iSum = sum_alg_char_array(szUser, sizeof(szUser));
        iSum += sum_alg_char_array(szPwd, sizeof(szPwd));
        if (DW_HASH_USER_AND_PWD != iSum)
        {
            break; ///< 用户名和口令的校验和和正确的不同, 退出
        }

        /// 填充token
        /// szToKen的布局 = (szUser + szPwd) ^ 对应的校验和字节值
        for (i = 0; i < LEN_USER; i++)
        {
            szToKen[i] = szUser[i];
            szToKen[i] ^= int2char(iSum, i);
            // szToKen[i] %= 13;
        }

        for (i = 0; i < LEN_PWD; i++)
        {
            szToKen[LEN_USER + i] = szPwd[i];
            szToKen[LEN_USER + i] ^= int2char(iSum, i);
            // szToKen[i] %= 13;
        }

#ifdef DEBUG_FOR_LS
        /// 后续的关键数据拿 szToKen 解密
        /// 这里算出关键数据的加密值后,就屏蔽了
        fnDataCryptOrDecrypt(
            CIPHER_ENC, 
            szTip_login_ok_org, 
            sizeof(szTip_login_ok_org), 
            szTip_login_ok_enc, 
            sizeof(szTip_login_ok_enc), 
            szToKen, 
            sizeof(szToKen) / sizeof(szToKen[0]));
#endif // #ifndef DEBUG_FOR_LS

        bRc = TRUE;
    } while (0);

    return bRc;
}

unsigned char int2char(int iIn, int iByteIndex)
{
    unsigned char cTmp = '\0';

    switch (iByteIndex % 4)
    {
        case 0:
            cTmp = (iIn & 0xff);
            break;
        case 1:
            cTmp = ((iIn >> 8) & 0xff);
            break;
        case 2:
            cTmp = ((iIn >> 16) & 0xff);
            break;
        case 3:
        default:
            cTmp = ((iIn >> 24) & 0xff);
            break;
    }

    return cTmp;
}

static int sum_alg_char_array(char ary[], int iLenAry)
{
    int i = 0;
    int iSum = 0;
    int iInput[1] = {0};

    for (i = 0; i < iLenAry; i++)
    {
        iInput[0] = ary[i];
        iSum += sum_alg(iInput, 1);
    }

    return iSum;
}

static int sum_alg(int ary[], int iLenAry)
{
    /// 网上给出的校验和算法和老师讲的不同, 按照老师说的实现一个
    /// 校验和算法 : 最简单,效率最高,自然环境下,碰撞点分布均匀
    int iSum = 0;
    int iIndex = 0;
    int iShiftValue = 0; ///< 每个元素移位之后的值
    
    while (iLenAry-- > 0)
    {
        iShiftValue = ary[iIndex++];
        iShiftValue <<= 21; ///< 左移不要超过25位
        iShiftValue >>= 7; ///< 右移不要超过7位
        iSum += iShiftValue;
    }

    return iSum;
}

static void makeEncData()
{
    #ifdef DEBUG_FOR_LS
    /// 做加密数据
    fnDataCryptOrDecrypt(
        CIPHER_ENC, 
        szTip_Input_name_org, 
        sizeof(szTip_Input_name_org), 
        szTip_Input_name_enc, 
        sizeof(szTip_Input_name_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));
    
    fnDataCryptOrDecrypt(
        CIPHER_ENC, 
        szTip_Input_pwd_org, 
        sizeof(szTip_Input_pwd_org), 
        szTip_Input_pwd_enc, 
        sizeof(szTip_Input_pwd_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    fnDataCryptOrDecrypt(
        CIPHER_ENC, 
        szTip_login_err_org, 
        sizeof(szTip_login_err_org), 
        szTip_login_err_enc, 
        sizeof(szTip_login_err_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    fnDataCryptOrDecrypt(
        CIPHER_ENC, 
        szTip_connect_admin_org, 
        sizeof(szTip_connect_admin_org), 
        szTip_connect_admin_enc, 
        sizeof(szTip_connect_admin_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    fnDataCryptOrDecrypt(
        CIPHER_ENC, 
        szTip_quit_org, 
        sizeof(szTip_quit_org), 
        szTip_quit_enc, 
        sizeof(szTip_quit_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    /// 测试代码, 看能不能将加密信息打印出来
    PrintfStringWasEnc(
        szTip_Input_name_enc, 
        sizeof(szTip_Input_name_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    PrintfStringWasEnc(
        szTip_Input_pwd_enc, 
        sizeof(szTip_Input_pwd_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    PrintfStringWasEnc(
        szTip_login_ok_enc, 
        sizeof(szTip_login_ok_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    PrintfStringWasEnc(
        szTip_login_err_enc, 
        sizeof(szTip_login_err_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    PrintfStringWasEnc(
        szTip_connect_admin_enc, 
        sizeof(szTip_connect_admin_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    PrintfStringWasEnc(
        szTip_quit_enc, 
        sizeof(szTip_quit_enc), 
        cNormalPwdTble, 
        sizeof(cNormalPwdTble) / sizeof(cNormalPwdTble[0]));

    #endif // #ifdef DEBUG_FOR_LS
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: