首页
社区
课程
招聘
[分享]WinLicense Updated 2.0.5.0 License Structure Reversed
2009-9-1 19:26 3124

[分享]WinLicense Updated 2.0.5.0 License Structure Reversed

2009-9-1 19:26
3124
char *LicenseHash = "LAvi4vZ1CoV9Pyfhsbk75Z3pZp4p49OTPf8ez4IlaM00QBxfz9HQyDalE6v872l643gxg6AC4864
6c5iIfjm3z8tt1leaGXUsk8z"

              "KK19wyTLB23ZBobk228mS75fGjIep11NH2t433410Ii49aR20fffbfffb020100028181006e454
c3dc28fb834ea064dd64323a"

              "e1cf77c83f172a8b4d02875d0e33e0b758274a6be1c2bfe4c88c3eec36e43ef2cf82a0746680
d0601cd6bd3a3ce8b93af6a7"

              "a6076bc2c04d77771237f49464296c7d2cce29d903a9b86b5a83ac527b7add4c0583b2dcb220
9485a9b1f81fe831cea73d0b"

              "ff74377b7eaff320d513fcb8b2902030100010281801124258f5e2cb0224d94b049d3c2faa05
71a5c7a4e6c0a3b6766b5137"

              "6041afeadfa7387f690bfbdecd3333ef3417d389073f40e5da3e6e8d34fa1618c91e70d0e6ea
cd7665e760cec0098214ea1f"

              "ba9b9d171e90eeb263ecf09625d20bf1cfe5fffcab1339c50117636b32cab47122cb225f677c
5968d7bdcb1eaabb6f2b1470"

              "240b0ad37f9efd3286f17a2b7e8d34bff107aa60d4297022604ab4aa895a266ed72cd8d2bbaf
80146b9133b259b6eb562eec"

              "6d76a94f4044bb1f8e3031f7905713702409fc78ad8d2175022f279734f8b179ac064257bb88
1e0e4baafb5593b16fe692c5"

              "c818a879c78eebde92ce795c2dc00395bdddd635069014a051207c75d8c969f0241007c254b9
719b933c9543f67a17790082"

              "ba93333501e52492ab0be6655b6e74264902169a01892b502698bff320809f6f9b7c938c06ff
2f0c99f0ccd6df91924e3024"

              "091670dbbf2b4b48099185d0f6e0cb50f90136c5ba415fd10c705c986348ea13775978d718bb
ba1c7c182d3dd3dcee7854b4"

              "cc443b4d15a12fa3a4649efa0191102409cdfda5836f6a0c171855d9c05814681d8b4456ccea
20115d04a03c4feae4bea4e0"

              "e350e9cf046ebf213d67ec8eddd63a3fa491a4b0115b9afbce000b2271badfffefffe0201000
2820100aa4e25f7bf872578b"

              "52d45b6dcc68b20f58d98c01cf756c4c7bfb790d611fbd14be02cb01665a7f2afe1004f9d72e
0b21f98f0525f6c5a04d8385"

              "c0d4f643c976f6a6204c2bb7c546e85d6179334b35ec975d411fac2af3f4fee1c5c0e3f8b42d
0fe2cc17ed9f914be0f739ef"

              "727b5207333240c8dd1cb6c93d24a47088619912cf7a1cd57a638d7d1f2b0a71fb7ee99624db
f4a3c552947211fea3dc0443"

              "99049adc7d9eb62281d07b2e70af429159acecaeca3052f67155d23d7cffba16d54b14803a74
19bab2764b84ee88dbcda088"

              "b8c09fd8aa8f1b168e910d219fb6d14c39354d139b586ea6412d868b34cbbbf5a3737f3a9edb
33728dad6e3d871a5a502030"

              "100010282010001f2a80aaea134d6432f914a7a0eccf4be4ceae2eda1e2ec9817f303f57d84a
abc3faee5d507bf75438f8da"

              "c461c7ed742b71783eb02a75542af83015af7b0f2b976971d94a8462530136df8b1e4152b751
f4378462ce25f6ac25f86d50"

              "48de04b2ed10e65d7f28fa06c8c51bf39701ffecea65a52129a229e8935f4c7334373bf0b6da
992299358930a3951521ba0b"

              "9078d281ae3c691a1e74359242c03925ba6a5a11816adb08680e2647242483e5ad99ad4cf565
3dcf398d7e97922355efb7b6"

              "aba92e1e7564dbfc795538b9b62138e06cd8864223b65fc7de1c2c841beea40cf5f4de8e2dc2
91465901a4e4aa338de73ef2"

              "400723e9b099a8c48f435ad71028180f48effd9767e05db6744898d974bc431b0474a5882cd6
c0856eacbff60cda7bd58de5"

              "b7744519d8201de2d15fa546642bad35bb385eee6d641046ff6f270bf52b30b03cfcb1438cf0
e3e3ed464e13796cac62e379"

              "633636ae3cc124880480b6c75d4afa1439159b95d05a14b3aa95119b3b698ab5a027a0dd7653
037bcdad0b5028180b245d72"

              "525aaf1557ab7234c9db32cc53c6bb8ce5c64d9929cd016a34bff9efb6187ef2bd49766e1024
7d2116a3f7a58f95a0a0fcf3"

              "6baa91be453f0411ceb8837b67fd8aa82067acd9c9b17748ee666729591d2fd61d264451f699
b18efdb94dfb3f649c44cf8f"

              "ccfd8d1f48d937219f6f1021e4dba89dd1d9366ce8be7c731028180ef27bc6993e7afa09c7f3
8a8df50b79f03cce39664eba"

              "fff03c87f0fd141ac0c8d907d0fc81eac120bf3925190c8e26bd53985ceac6631154ae5a4fc7
09ff369532fad5d9231c7502"

              "c94906ab1f050a544ccc33b96c5d02e2270595ccf1e2515beb0ebc39f48cfde666a700e1a62a
3ada7c223d045a8706582c33"

              "081014d5695028180115f00d1dbd3c6645feacc83c0b21ee0b13c85eb85d145ea256199731c0
ab2812845c8a66ab6be0d9ad"

              "d48b8edb375c689b59e596005a336ab431a72c4c57ea5ed57d92951a40de1957b771958003ca
f2ae72c28750c3d260c1e3d7"

              "a2179edd999dabd5afec7c9534925857fe0f3c720849183755479a2c96b025bf83065cb61028
180cc2bc4ea381710bba2232"

              "ada7b6691d01276608a8e4cbc108fb02909536139f4b434d4d6abb13139a6e4b6106d1ac92ef
fd9864ddfe23b40d7c4c791c"

              "b3cc001b1553d1b166795f73b5ff4d1a5079223e784e39f6b9fb46548e9400ffaf23177fea77
3a8ffb85450d7575fd8b449b"

              "960c79c168d67f3f46550619f0513fe4b78";

If you look depper, you will see two very interesting values in the hash, fffefffe and fffbfffb, so now lets play with this and you got this structure

reg_hash (fffbfffb) private_key2 (fffefffe) private_key

reg_hash Can have Capitals letters as you can see
private_key and private_key2 can only hold 0..9 and a..f (non-capitals)

Pretty nice start isn't it? Later you will find the use for this.

License Structure

This the main estructure

CODE
struct t_WL_License_File
{
    DWORD unk0;    // 0 :: DWORDs reg_hash[8] + reg_hash[C]
    BYTE unk4;    // 4 :: expiration_days Value if 0 then RDTSC
    BYTE unk5;    // 5 :: executions Value if 0 then RDTSC
    DWORD unk6;    // 6 :: expire_date Value if 0 then RDTSC
    DWORD unkA;    // A :: global_time Value if 0 then RDTSC
    DWORD unkE;    // E :: country Value if 0 then RDTSC
    DWORD  unk12;    // 12 :: run_time | expiration_days Value if 0 then RDTSC
    DWORD  unk16;    // 16 :: DWORDs reg_hash[10] + reg_hash[14]
    BYTE unk1A;    // 1A :: CheckSum HWID
    WORD unk1B;    // 1B :: CheckSum HWID
    WORD unk1D;    // 1D :: CheckSum HWID
    WORD unk1F;    // 1F :: CheckSum HWID
    WORD unk21;    // 21 :: CheckSum HWID
    WORD unk23;    // 23 :: RDTSC
    WORD unk25;    // 25 :: Flags
    DWORD unk27;    // 27 :: RDTSC
    WORD unk2B;    // 2B :: CheckSum User
    WORD unk2D;    // 2D :: CheckSum from 0..2D
    DWORD unk2F;    // 2F :: RDTSC
    WORD unk33;    // 33 :: WORDs reg_hash[18] + (DWORDs reg_hash[18] >> 0x10);
    WORD unk35;    // 35 :: CheckSum User
    WORD unk37;    // 2D :: CheckSum from 0..37
    DWORD unk39;    // 39 :: Always is 0xFFFFFFFF
    DWORD unk3D;    // 3D :: Always is 0xFFFFFFFF
    BYTE unk41[0x2000 - 0x41];    // Empty Slots for other purposes
};

RDTSC is Time Stamp Counter ( an asm instruction) return its values in eax:edx, is like a rand() function

Unk0
is the result of the next operation = *(DWORD *)((LPBYTE)hash_key + 0x08) + *(DWORD *)((LPBYTE)hash_key + 0x0C);
Hey! so this value is checked if the License belong to that program!, nice start to avoid corrupt license message!, but is not as easy as i said xd, but for example look, reg_hash has this feautres, can hold from '0' (0x30) to 'z' (0x7A), so theoperation and the result will be between 0x60 to 0xF4, for eaxmple
0x5456886D - you would bever find this value on unk0 position! why? 0x54 does not belong to the range as well as 0x56
0xF5A6E89D - the same 0xF5 does not belong to the range!
0xCCA6E89D - ... Yes you can find it
Well, nice to see, but why do i need this?, simple, with this limitations you can discard values from Virtual Machine when comapring this values.

Unk4
Will hold the expirations days from the License, ONLY if the value is below 255!

Unk5
Contains the number of executions before license expires

Unk6
Contains the expire date in this format year - month - day
day is a byte value, is on the 0..7 bit
month is a byte value, is on 8..15 bit
year is a word value, is on a 16-32 bit
For example 07D70204 says that will license will expire on 2007-March-04

UnkA
Contains the Global Time before license expires

UnkE
Contains the locked country

Unk12
Well, i think here is a bug, coz on generated license one value destroys another, maybe i reversed i little bad

CODE
    if ( run_time != 0 && expiration_days > 255 )
        WinLicenseFile->unk12 = expiration_days | 0x80000000;
    if ( run_time == 0 && expiration_days > 255 )
        WinLicenseFile->unk12 = expiration_days | 0x80000000;
    else if ( run_time != 0 && expiration_days <= 255 )
        WinLicenseFile->unk12 = expiration_days;
    else if ( run_time == 0 && expiration_days <= 255 )
        WinLicenseFile->unk12 = RDTSC();

Unk16
Same as unk0

Unk1A
Take for example this HWID
105A-DF45-3533-AACC-328D-DEDF-6789-ABCD
Conatins Checksum of HarwareID, is the result of the addition between Orange and purple (0x6A)

Unk1B
Take for example this HWID
105A-DF45-3533-AACC-328D-DEDF-6789-ABCD
Conatins Checksum of HarwareID, is the result of the addition between Orange and purple

Unk1D
Take for example this HWID
105A-DF45-3533-AACC-328D-DEDF-6789-ABCD
Conatins Checksum of HarwareID, is the result of the addition between Orange and purple

Unk1F
Take for example this HWID
105A-DF45-3533-AACC-328D-DEDF-6789-ABCD
Conatins Checksum of HarwareID, is the result of the addition between Orange and purple

Unk21
Take for example this HWID
105A-DF45-3533-AACC-328D-DEDF-6789-ABCD
Conatins Checksum of HarwareID, is the result of the next operation

CODE
unk1A ^ unk1B ^ unk1D ^ unk1F ^ *(WORD *)((LPBYTE)reg_hash + 0x64);

This is very special coz also have the a reg_ash value

Unk23
Random Value

Unk25
FLAGS!!, yea, what are you looking for, this contains which restructions are applied to every application

CODE
    if ( expiration_days <= 255 )
        wLicenseFlags |= 1;

    if ( executions != 0 )/*25*/
        wLicenseFlags |= 2;

    if ( expire_date != NULL )
        wLicenseFlags |= 4;

    if ( hwid != NULL )
        wLicenseFlags |= 8;

    if ( country != 0 )
        wLicenseFlags |= 0x40;
   
    if ( run_time != 0 || expiration_days > 255 )
        wLicenseFlags |= 0x20;

    if ( global_time != 0 )
        wLicenseFlags |= 0x10;

Unk27
Random Value

Unk2B
Contains the addition of Checksums Of User, Company, CustomData and HWID ( yeah aother check for Hardware ID )

Take this function for example

CODE
DWORD CreateCheckSumStr(const char * szString)
{
    BYTE magic_high = 0;
    BYTE magic_low  = 0;
    BYTE handler = 0;
   
    for(int i=0;szString[i] != 0; i++)
    {
        if ( handler != 0 )
        {
            magic_low ^= szString[i];
            handler--;
        }
        else
        {
            magic_high += szString[i];
            handler++;
        }
    }

    return MAKEWORD(magic_low, magic_high);
}

So unk2B is CreateCheckSumStr(user) + CreateCheckSumStr(company) + CreateCheckSumStr(CustomData) + CreateCheckSumStr(HWID)
Caution.- If in you application is enabled the Network instances you will see that CustomData Is a Little different, take for example this custom data

Without Network instances : 'This is Custom Data'
With Network instances : '*NL*0003This is Custom Data' <- in this case You got network instances ( is 3 ), *NL* is like a 'flag', that tells WL that Application have Network Instances, now, The CreateCheckSumStr in this case is only the purple data (not the *NL*)
CreateCheckSumStr(CustomData + 0x08);

Unk2D
Is the Result of a Checksum of the generated license from 0..2C

CODE
    BYTE magic_h = 0;
    BYTE magic_l = 0;
    BYTE handler = 0;
    for( i=0; i< 0x2D; i++ )
    {
        if ( handler != 0 )
        {
            magic_l += lpWLBuffer[i];
            handler--;
        }
        else
        {
            magic_h ^= lpWLBuffer[i];
            handler++;
        }
    }
    WinLicenseFile->unk2D = MAKEWORD(magic_l, magic_h);

Unk2F
Random Value

Unk33
is the result of the next operation = *(WORD *)((LPBYTE)hash_key + 0x18) + *(WORD *)((LPBYTE)hash_key + 0x1A);

Unk35
Same as unk2B

Unk37

Is calculated acordind this

CODE
    magic_h = 0;
    magic_l = 0;
    handler = 0;
    for( i=0; i< 0x37; i++ )
    {
        if ( handler != 0 )
        {
            magic_l += lpWLBuffer[i];
            handler--;
        }
        else
        {
            magic_h ^= lpWLBuffer[i];
            handler++;
        }
    }

Unk39
Always is 0xFFFFFFFF

Unk3D
Always is 0xFFFFFFFF

Unk41 to the end
This part contains the user, company, customdata (including *NL* part) and HWID, remember, this are NULL terminatedStrings, adn the separation between then are the 0xFFFFFFFF. Here you got an example

CODE
77E462E0  75 73 65 72 00 FF FF FF  user.ÿÿÿ
77E462E8  FF FF FF FF FF 63 6F 6D  ÿÿÿÿÿcom
77E462F0  70 61 6E 79 20 6E 6F 6E  pany non
77E462F8  65 00 FF FF FF FF FF FF  e.ÿÿÿÿÿÿ
77E46300  FF FF 2A 4E 4C 30 30 32  ÿÿ*NL002
77E46308  33 44 65 61 69 6C 74 73  3Deailts
77E46310  20 6F 66 20 63 75 73 74   of cust
77E46318  6F 6D 65 72 00 FF FF FF  omer.ÿÿÿ
77E46320  FF FF FF FF FF 31 32 33  ÿÿÿÿÿ123
77E46328  34 2D 35 36 37 38 2D 39  4-5678-9
77E46330  41 42 43 44 2D 45 46 31  ABCD-EF1
77E46338  32 2D 33 34 35 36 2D 37  2-3456-7
77E46340  38 39 41 2D 32 34 33 34  89A-2434
77E46348  2D 31 31 31 31 00 FE FF  -1111.þÿ
77E46350  FF FF FE FF FF FF 23 42  ÿÿþÿÿÿ#B
77E46358  34 23                    4#

note that after HWID the end is -2, not -1(0xFFFFFFFF),
But i put another Value after that, this is another checksum i mean the 0x23344223

This is calculated with this operation

CODE
    dwOffset = 0;
    BYTE magic_cl = 0;
    BYTE magic_ch = 0;
    BYTE magic_bl = 0;
    BYTE magic_bh = 0;
    handler = 0;
    while ( *(DWORD *)(lpWLBuffer + dwOffset) != -2 &&  *(DWORD *)(lpWLBuffer + dwOffset + 4) != -2 )
    {
        if ( handler == 0 )
            magic_bl += lpWLBuffer[dwOffset];
        else if ( handler == 1 )
            magic_bh += lpWLBuffer[dwOffset];
        else if ( handler == 2 )
            magic_cl ^= lpWLBuffer[dwOffset];
        else if ( handler == 3 )
            magic_ch ^= lpWLBuffer[dwOffset];

        handler++;
        
        if ( handler == 4 )
            handler = 0;

        dwOffset++;
    }

    *(DWORD *)(lpWLBuffer + dwOffset + 8) = MAKELONG(MAKEWORD(magic_cl,magic_ch), MAKEWORD(magic_bl,magic_bh));

Howevber you will find this is not the end, you will find 0x100 more bytes after this Checksum Value, this vlues are a rsa sign, made from LicenseUnique Hash

This is the structure, but it not all, in the process, some parts are encrypted, many times, that i will complete later

Tracing License Building
The text above is just for say what you would find on a decrypted License File, but first it is necesary to decrypt it

So Here is the values set before the first encrypt (in order )

CODE
    WinLicenseFile->unk0
    WinLicenseFile->unk16
    WinLicenseFile->unk27
    WinLicenseFile->unk33
    WinLicenseFile->unk2F
    WinLicenseFile->unk1A
    WinLicenseFile->unk1B
    WinLicenseFile->unk1D
    WinLicenseFile->unk1F
    WinLicenseFile->unk21
    WinLicenseFile->unk2B
    WinLicenseFile->unk35
    WinLicenseFile->unk25
    WinLicenseFile->unk4
    WinLicenseFile->unk5
    WinLicenseFile->unk6
    WinLicenseFile->unkE
    WinLicenseFile->unk12
    WinLicenseFile->unkA
    WinLicenseFile->unk23

Now Here is the first crypt

CODE
    for( DWORD i=0; i< 0x23; i++ )
    {
        WinLicenseFile[i] ^= LOBYTE(WinLicenseFile->unk23);
        WinLicenseFile[i] += HIBYTE(WinLicenseFile->unk23);
    }

So unk23 is used to crypt the bytes from 0..22
Now, a Checksum is created

CODE
    WinLicenseFile->unk2D

Now the Second Crypt begins, take note that it uses the hash, so you nknow the range

CODE
    //////////////////////////////////////////////////////
    // Method 01
    DWORD dwMagicKey_01[4];
    dwMagicKey_01[0] = *(DWORD *)((LPBYTE)hash_key + 0x1C) + *(DWORD *)((LPBYTE)hash_key + 0x2C);
    dwMagicKey_01[1] = *(DWORD *)((LPBYTE)hash_key + 0x20) + *(DWORD *)((LPBYTE)hash_key + 0x30);
    dwMagicKey_01[2] = *(DWORD *)((LPBYTE)hash_key + 0x24) + *(DWORD *)((LPBYTE)hash_key + 0x34);
    dwMagicKey_01[3] = *(DWORD *)((LPBYTE)hash_key + 0x28) + *(DWORD *)((LPBYTE)hash_key + 0x38);
    Crypt_Method_01(lpWLBuffer, 0x33, dwMagicKey_01);

void __stdcall Crypt_Method_01(LPBYTE lpBuffer, int iBufferLen, LPDWORD pMagicKey)
{
    __asm
    {
        PUSHAD
        MOV EDI,DWORD PTR SS:[EBP+0x8]
        MOV ECX,DWORD PTR SS:[EBP+0xC]
        SHR ECX,0x3
        JMP SHORT ELoop
SLoop:    PUSH 0x20
        PUSH DWORD PTR SS:[EBP+0x10]
        PUSH EDI
        CALL Method_01
        ADD EDI,0x8
        DEC ECX
ELoop:    OR ECX,ECX
        JNZ SHORT SLoop
        POPAD
    }
}

void __stdcall Method_01(void * pBuffer, void * pKey, int len)
{
    __asm
    {
        PUSHAD
        MOV EDI,DWORD PTR SS:[EBP+0x8]
        MOV ESI,DWORD PTR SS:[EBP+0xC]
        MOV EBX,DWORD PTR DS:[EDI]
        MOV ECX,DWORD PTR DS:[EDI+0x4]
        XOR EAX,EAX
        JMP SHORT ELoop
SLoop:    ADD EAX,0x9E3779B9
        MOV EDX,ECX
        SHL EDX,0x4
        ADD EBX,EDX
        MOV EDX,DWORD PTR DS:[ESI]
        XOR EDX,ECX
        ADD EBX,EDX
        MOV EDX,ECX
        SHR EDX,0x5
        XOR EDX,EAX
        ADD EBX,EDX
        ADD EBX,DWORD PTR DS:[ESI+0x4]
        MOV EDX,EBX
        SHL EDX,0x4
        ADD ECX,EDX
        MOV EDX,DWORD PTR DS:[ESI+0x8]
        XOR EDX,EBX
        ADD ECX,EDX
        MOV EDX,EBX
        SHR EDX,0x5
        XOR EDX,EAX
        ADD ECX,EDX
        ADD ECX,DWORD PTR DS:[ESI+0xC]
        DEC DWORD PTR SS:[EBP+0x10]
ELoop:    CMP DWORD PTR SS:[EBP+0x10],0
        JA SHORT SLoop
        MOV DWORD PTR DS:[EDI],EBX
        MOV DWORD PTR DS:[EDI+0x4],ECX
        POPAD
    }
}

Now, after this encryption, another is made (what i call Method 2), take a look, this time hash_key is NOT altered, so you can find the original one in the encrypted application, like an null terminate string

CODE
    //////////////////////////////////////////////////////
    // Method 02
    DWORD dwMagicKey_02[9];
    dwMagicKey_02[0] = *(DWORD *)((LPBYTE)hash_key + 0x44);
    dwMagicKey_02[1] = *(DWORD *)((LPBYTE)hash_key + 0x48);
    dwMagicKey_02[2] = *(DWORD *)((LPBYTE)hash_key + 0x4C);
    dwMagicKey_02[3] = *(DWORD *)((LPBYTE)hash_key + 0x50);
    dwMagicKey_02[4] = *(DWORD *)((LPBYTE)hash_key + 0x54);
    dwMagicKey_02[5] = *(DWORD *)((LPBYTE)hash_key + 0x58);
    dwMagicKey_02[6] = *(DWORD *)((LPBYTE)hash_key + 0x5C);
    dwMagicKey_02[7] = *(DWORD *)((LPBYTE)hash_key + 0x60);
    dwMagicKey_02[8] = 0;
    Crypt_Method_02(lpWLBuffer, 0x33, dwMagicKey_02);

void __stdcall CLicense::Crypt_Method_02(LPBYTE lpBuffer, int iBufferLen, LPDWORD pMagicKey)
{
    Method_02(lpBuffer, iBufferLen, pMagicKey);
}

void __stdcall Method_02(void * pBuffer, int len, void * pKey)
{
    __asm
    {
        PUSHAD
        MOV EAX,DWORD PTR SS:[EBP+0x8]
        MOV ECX,DWORD PTR SS:[EBP+0xC]
        MOV EDX,DWORD PTR SS:[EBP+0x10]
        MOV EDI,EAX
        MOV ESI,EDX
        MOV EAX,0x41363233
        XOR AL,BYTE PTR DS:[ESI]
        CALL SubVarian_Method_02
        MOV EBX,EAX
        XOR AH,BYTE PTR DS:[ESI]
        CALL SubVarian_Method_02
        SHR ECX,0x2
        MOV EDX,ECX
label1: XOR DWORD PTR DS:[EDI],EAX
        MOV CL,AL
        ADD EDI,0x4
        ROL EBX,CL
        XOR EAX,EBX
        MOV CL,BH
        ROR EAX,CL
        ADD EBX,EAX
        DEC EDX
        JNZ SHORT label1
        POPAD
    }
}

void __declspec(naked) SubVarian_Method_02()
{
    __asm
    {
        PUSH ECX
        PUSH ESI
        PUSH EDX
        XOR EDX,EDX
        DEC ESI
label2:    INC ESI
        XOR AH,BYTE PTR DS:[ESI]
label1:    XOR AL,DL
        ADD EAX,0x7034616B
        MOV CL,AL
        ROR EAX,CL
        XOR EAX,0x8372A5A7
        DEC DX
        JNZ SHORT label1
        CMP BYTE PTR DS:[ESI],0
        JNZ SHORT label2
        POP EDX
        POP ESI
        POP ECX
        RETN
    }
}

Now, the next values are set

CODE
    WinLicenseFile->unk37 -- Checksum
    WinLicenseFile->unk39
    WinLicenseFile->unk3D
WinLicenseFile User, Company and Custom Data and HWID

After this, again the License File is encrypted using unk0, thi part Crypts the Usser, Company and Custom Data and HWID

CODE
    DWORD dwMagic_02 = WinLicenseFile->unk0;

    __asm
    {
        pushad
        mov esi, dword ptr ss:[lpWLBuffer]
        add esi, 0x39
        mov eax, dword ptr ss:[dwMagic_02]
        jmp Init
Start:    xor byte ptr ds:[esi], al
        add byte ptr ds:[esi], ah
        ror eax, 1
        inc esi
Init:    cmp dword ptr ds:[esi],   -2
        jnz Start
        cmp dword ptr ds:[esi+4], -2
        jnz Start
        popad
    }

Finally after the 0xFFFFFFFE 0xFFFFFFFE (after HWID ) is created the last Checksum according to the algorithm i put above

Now, we finish with the first stage of protection, here comes the second one

WinLicense Creates a 'sign', according to the License Unique Hash, beetween the fffefffe and the end (i mean private_key), it is always 0x100 bytes
- Using LibTomCrypt lib should be

CODE
rsa_import(Private_Key, Private_Key_Size, &RSA_Key);
WLRegisterSignature((unsigned char *)(&WLLicenseFileKey), iLicenseSize, Signature, &SignatureLen, &RSA_Key);

void WLRegisterSignature(unsigned char * WLStruct, unsigned long WLStructSize, unsigned char * SignatureOut, unsigned long * SignatureLen, rsa_key * key)
{
    unsigned char sign[1024];
    unsigned long hash_memory_len = 0x400;

    register_hash(&sha1_desc);
    int hash_id = find_hash("sha1");
    sign[0] = 0;
    memset(sign + 1, 0, sizeof(sign)-1);
    hash_memory(hash_id, WLStruct, WLStructSize, sign, &hash_memory_len);
    rsa_v15_sign_hash(sign, hash_memory_len, SignatureOut, SignatureLen, hash_id, key);
}

Now it crypt using rsa algorithm

CODE
            iLicenseSize += SignatureLen;
            unsigned long LicOfs = 0x7F;
            unsigned long NewLicenseSize = 0;

            if (iLicenseSize > 0x7F )
            {
                while ( LicOfs < iLicenseSize )
                {
                    output_buffer += WLRsaProtect(output_buffer, (unsigned char *)(&WLLicenseFileKey), hash_key);
                    LicOfs += 0x7F;
                    NewLicenseSize += 0x7F;
                }
            }

            memcpy(output_buffer, (unsigned char *)(&WLLicenseFileKey) + NewLicenseSize, iLicenseSize - NewLicenseSize);

unsigned long __stdcall WLRsaProtect(unsigned char * OutputBuffer, unsigned char * WLLicenseStruct, const char * hash_key)
{
    unsigned char crypt_key[0x1000];
    rsa_key key;
    unsigned long key_pos_1 = Find_substring(hash_key, "fffbfffb") + 8;
    unsigned long key_pos_2 = Find_substring(hash_key, "fffefffe");
    HexToNumber(hash_key + key_pos_1, crypt_key, (key_pos_2 - key_pos_1) / 2);
    unsigned long ProtectSize = 0x7F;
   
    if ( rsa_import(crypt_key, (key_pos_2 - key_pos_1) / 2, &key) != CRYPT_OK )
    {
        printf("Error importing private key");
        return 0;
    }

    ProtectSize = 0xFE;
    rsa_exptmod(WLLicenseStruct, 0x7F, OutputBuffer, &ProtectSize, PK_PRIVATE, &key);
    return ProtectSize;
}

This part is more difficult, since it uses rsa, but is pretty interesting once you got it

Licenses on 2.0.5.0

Here is and update to 2.0.5.0, the changes are that HWID is Wchar null termitated strings, Net instances are no longer stored on CustomData String, and there is some new params, Like dwLocalTime (Strores year, month and day, format similar to ExpirationDate), InstallDate

CODE
    // Copy HWID
    if ( hwid == NULL )
        *(BYTE *)(lpWLBuffer + dwOffset++) = 0;
    else
        dwOffset += strlen(strcpy((char *)(lpWLBuffer + dwOffset), hwid)) + 1;

    *( BYTE*)(lpWLBuffer + dwOffset) = 0;    // WL Change V2
    dwOffset++;
    *(DWORD *)(lpWLBuffer + dwOffset) = -3;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = -3;
    dwOffset += 4;

    // WL Change V2
    *(DWORD *)(lpWLBuffer + dwOffset) = 0x83A9B0F1; // CONSTANT
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = 0x18; // CONSTANT
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = MAKELONG(MAKEWORD(rand(),rand()),MAKEWORD(rand(),rand()));
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = InstallDate;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = NetInstances;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = dwLocalTime;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = -3;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = -3;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = -2;
    dwOffset += 4;
    *(DWORD *)(lpWLBuffer + dwOffset) = -2;
    dwOffset += 4;

[竞赛]2024 KCTF 大赛征题截止日期08月10日!

收藏
免费 0
打赏
分享
最新回复 (5)
雪    币: 218
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hxqlky 2009-9-1 19:27
2
0
WinLicense Updated 2.0.5.0 License Structure Reversed
First how WL make unique Licenses for each program?, easy, as you can ses on the pic above, there is an 'hash', specific for each program, now this hash have three hashes insid, but how WL recognize them?, easy. Take for example my hash
/* C/C++ Format */
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
moritenw 2010-4-27 14:25
3
0
没看完,不错,谢谢分享
雪    币: 111
活跃值: (29)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
knightsoft 2010-5-4 00:50
4
0
非常不错的文章,谢谢分享
雪    币: 211
活跃值: (152)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hovey 2010-5-14 12:50
5
0
E文有点看不懂
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jdzlifei 2010-5-18 18:50
6
0
学习下,顶一下
游客
登录 | 注册 方可回帖
返回