#include "Hook.h"
#include <stdio.h>

// dllmain.cpp : Defines the entry point for the DLL application.

// ripped from openssl
typedef struct bignum_st {
    unsigned long* d;
    int top;
    int dmax;
    int neg;
    int flags;
} BIGNUM;

typedef struct rsa_st {
    void* unk1;
    void* unk2;
    void* unk3;
    void* unk4;
    BIGNUM* m;
    BIGNUM* e;
    void* unk5;
    void* unk6;
} RSA;

using openssl_rsa_public_decrypt_ptr = int(__cdecl*)(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding);
static openssl_rsa_public_decrypt_ptr RsaPublicDecrypt = nullptr;

using openssl_sha1_ptr = char* (__cdecl*)(const unsigned char* d, size_t n, unsigned char* md);
static openssl_sha1_ptr Sha1 = nullptr;

const size_t SHA1_SZ = 0x14;

char YOYO_LICENSE_PUBLIC_KEY[0x80] = {
    0x7B, 0x05, 0x78, 0xE0, 0x05, 0x50, 0xA4, 0xD6, 0xBA, 0xE9, 0x5E, 0x28, 0xF6, 0x74, 0x2A, 0x07,
    0x21, 0x08, 0xB8, 0xC0, 0x71, 0x38, 0xA3, 0x44, 0xCD, 0x87, 0xD0, 0xAB, 0x39, 0xA1, 0xF5, 0x56,
    0x94, 0x97, 0x3E, 0xF2, 0x03, 0x9C, 0xAD, 0x86, 0x37, 0x4B, 0x82, 0xC2, 0x8C, 0x40, 0x30, 0x85,
    0x39, 0x4F, 0x04, 0xBA, 0x4B, 0x65, 0xF6, 0x0E, 0x4B, 0x9A, 0x47, 0x59, 0xFE, 0xA0, 0xA6, 0x33,
    0xDC, 0x8A, 0x0C, 0x35, 0x58, 0xDF, 0x74, 0xDC, 0xB7, 0xFE, 0x57, 0x2C, 0x85, 0x14, 0xA6, 0xD2,
    0x34, 0x9E, 0x54, 0x7D, 0xCF, 0xEA, 0x08, 0x2D, 0x29, 0xB5, 0x0B, 0x01, 0x30, 0x14, 0x5A, 0x0C,
    0xBC, 0x28, 0xF2, 0x44, 0xAA, 0xA4, 0x59, 0xEF, 0xF4, 0x4A, 0x4D, 0xFE, 0x90, 0xF4, 0x19, 0x4D,
    0xAE, 0x9C, 0x8B, 0x26, 0x9B, 0x57, 0xE5, 0x7A, 0xFC, 0x93, 0x31, 0xE5, 0xA7, 0x43, 0xCA, 0xDD
};

static bool JustCheckedLicense = false;

char* SHA1(const unsigned char* d, size_t n, unsigned char* md) {
    // If the license was just checked, fake the SHA1 result as all 0xFF
    if (md != nullptr && JustCheckedLicense) {
        memset(md, 0xFF, SHA1_SZ);
        JustCheckedLicense = false;

        return (char*)md;
    }

    return Sha1(d, n, md);
}

int RSA_public_decrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) {
    
    // If the rsa key being used is the public key for license files,
    // set 0xFF as the result

    int res = RsaPublicDecrypt(flen, from, to, rsa, padding);

    if ( res == SHA1_SZ && memcmp(rsa->m->d, YOYO_LICENSE_PUBLIC_KEY, rsa->m->dmax) == 0) {
        memset(to, 0xFF, SHA1_SZ);
        JustCheckedLicense = true;
    }

    return res;
}

// hook RSA Public Decrypt & SHA1 functions
void PatchLibeay32() {

    LPVOID pubdecPtr = IAT::Hook("libeay32.dll", "RSA_public_decrypt", &RSA_public_decrypt);
    if (pubdecPtr == nullptr)
        return;

    RsaPublicDecrypt = (openssl_rsa_public_decrypt_ptr)pubdecPtr;

    LPVOID shaPtr = IAT::Hook("libeay32.dll", "SHA1", &SHA1);
    if (shaPtr == nullptr)
        return;

    Sha1 = (openssl_sha1_ptr)shaPtr;

}

void UnpatchLibeay32() {
    if(RsaPublicDecrypt != nullptr)
        IAT::Hook("libeay32.dll", "RSA_public_decrypt", &RsaPublicDecrypt);
    if(Sha1 != nullptr)
        IAT::Hook("libeay32.dll", "SHA1", &Sha1);
}