Jump to content
Tuts 4 You

Delphi; Help with string multiplication


dn5

Recommended Posts

Hello guys,

I have spent some time yesterday night to reverse Ziggy's Keygen me #1. Wasn't big deal, seriously, I found the routine and examine it in no-time. Thus I wanted to go deeper and create keygenerator.

Here is the algorithm (example of username: dn5):


004012C7 /$ 55 PUSH EBP
004012C8 |. 8BEC MOV EBP,ESP
004012CA |. 68 96334000 PUSH keygenMe.00403396 ; /StringOrChar = "DN5"
004012CF |. E8 8A000000 CALL <JMP.&user32.CharUpperA> ; \Uppercase every char in username
004012D4 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; /-> String: DN5 (into EAX)
004012D7 |. E8 D6000000 CALL <JMP.&kernel32.lstrlenA> ; \lstrlenA
004012DC |. 8BD0 MOV EDX,EAX ; EDX = EAX ('N5')
004012DE |. 85D2 TEST EDX,EDX ; EDX = Number of username characters
004012E0 |. 7E 6D JLE SHORT keygenMe.0040134F ; Jump if lower username character is lower then 3
004012E2 |. 33F6 XOR ESI,ESI ; XOR ESI with ESI to be 0 (in ESI there will be stored our correct key)
004012E4 |. B9 01000000 MOV ECX,1 ; Move 1 into ECX-------+
004012E9 |> 8B45 08 /MOV EAX,DWORD PTR SS:[EBP+8] ; Enter DN5 into EAX |
004012EC |. 8A4401 FF |MOV AL,BYTE PTR DS:[ECX+EAX-1] ; Take 1st, 2nd, and then 3th byte of EAX and put it into AL (EAX)
004012F0 |. 3C 20 |CMP AL,20 ; Compare AL with 20 (20=32)
004012F2 |. 74 0F |JE SHORT keygenMe.00401303 ; Jump to "INC ECX" if AL is d32
004012F4 |. 25 FF000000 |AND EAX,0FF ; And EAX with 0FF (255)
004012F9 |. 0FAF05 163640>|IMUL EAX,DWORD PTR DS:[403616] ; Pomnozi EAX (4E) with DWORD 403616 = (0007183E)
00401300 |. 48 |DEC EAX ; Decrement EAX
00401301 |. 03F0 |ADD ESI,EAX ; Add EAX to ESI
00401303 |> 41 |INC ECX ; Increment ECX
00401304 |. 4A |DEC EDX ; ...and decrement EDX
00401305 |.^ 75 E2 \JNZ SHORT keygenMe.004012E9 ; Jump if EDX is not zero (EDX=number of characters)
00401307 |. 8D15 D6344000 LEA EDX,DWORD PTR DS:[4034D6]
0040130D |. 8BC6 MOV EAX,ESI
0040130F |. 50 PUSH EAX ; /<%d>
00401310 |. 68 1F364000 PUSH keygenMe.0040361F ; |Format = "%d"
00401315 |. 52 PUSH EDX ; |s => keygenMe.004034D6
00401316 |. E8 3D000000 CALL <JMP.&user32.wsprintfA> ; \wsprintfA
0040131B |. 83C4 0C ADD ESP,0C ; Add h0C (12) into ESP
0040131E |. 68 1A364000 PUSH keygenMe.0040361A ; /String2 = "SnD-"
00401323 |. 68 56324000 PUSH keygenMe.00403256 ; |String1 = keygenMe.00403256
00401328 |. E8 7F000000 CALL <JMP.&kernel32.lstrcpyA> ; \lstrcpyA
0040132D |. 68 D6344000 PUSH keygenMe.004034D6 ; /StringToAdd = "1186236"
00401332 |. 68 56324000 PUSH keygenMe.00403256 ; |ConcatString = "SnD-1186236"
00401337 |. E8 64000000 CALL <JMP.&kernel32.lstrcatA> ; \lstrcatA
0040133C |. 68 56324000 PUSH keygenMe.00403256 ; /String2 = "SnD-1186236"
00401341 |. 68 16314000 PUSH keygenMe.00403116 ; |String1 = "SnD-1186236"
00401346 |. E8 5B000000 CALL <JMP.&kernel32.lstrcmpA> ; \lstrcmpA
0040134B |. C9 LEAVE
0040134C |. C2 0400 RETN 4
0040134F |> B8 01000000 MOV EAX,1
00401354 |. C9 LEAVE
00401355 \. C2 0400 RETN 4

Here is the final result of phished serial.

Username: dn5

Password: SnD-1186236

Which of course works. But as I said I have problem with coding a keygen. Note that I code in Delphi, probably Delphi developers will help me out. Here is my function that generates key.


function TForm1.getkey(hName:string):string;
var
i:integer; // Counter
charM:string; // Char from name
sName:String; // Name!
hEnd:integer; // End result
hDef:string; // Final hex!
preFinal:integer; // Prefinal result
preFinal2:integer; // Prefinal result
defFinal:integer; // Definitly final result
a,b,c:string;
d,e,f:integer;
sum:integer;
begin
sName := UpperCase(hName); // Uppercase username
// ->
for i := 1 to Length(sName) do // Do loop to end of username length
begin // ->
charM := Copy(sName, i, 1); // Copy 1st/2nd/3th char into charM
hEnd := Ord(charM[Length(charM)]); // AND EAX, 0FF-+
hDef := hDef + IntToHex(hEnd, 1); // -------------+
edit4.Text := hDef;
a := Copy(hDef, 1, 2);
b := Copy(hDef, 3, 2);
c := Copy(hDef, 5, 2);
// edit1.Text := edit1.text + hDef;
edit1.Text := a;
edit2.Text := b;
edit3.Text := c;(* preFinal := $44 * $1749;
preFinal2 := $4E * $1749;
defFinal := $35 * $1749; *) //<-WORKS FINE // Result:=a+'-'+b+IntToStr(StrToInt('$'+c)); <- ERROR //Result := IntToStr(StrToInt('$'))+IntToStr(+preFinal);
edit4.Text := result;
//edit4.Text := IntToStr(preFinal+preFinal2+defFinal);
end;
end;

As you can see reversed algorithm is ok. The problem is when I copy a, b, and c into edit1, edit2 and edit3. For example 'a' is 44h ('D'), 'b' is 4E('N') and 'c' is 35h('5'). And because a, b, c is string variable I can't multiplicate it or do any operation with it. I did try StrToInt() function, but 'b' and 'c' can not be reversed to integer for unknown reason. Maybe because 'b' is 4E and 'E' is not number. Just my prediction. If you look at the code in (* *) where is preFinal, preFinal2, and defFinal, that actually works fine and I got correct result in hex (serial). Don't worry about 'SnD-' as I can add that later.

Any help would be appriciated.

Link to comment

Thread can be locked. I was wrong about hex, I could easily transform chars into byte using Byte('D') and then that byte multiple with $1719 ;)

Example:


preFinal := Byte('D')*$1749;
preFinal2 := Byte('N')*$1749;
deffinal := Byte('5')*$1749; sum := prefinal + prefinal2 + deffinal;

Getting hex is unnecessery. Thread can be locked.

Link to comment

@Nacho_dj

Well kind alike mine, thus I function for generation valid key is:

function GenerateSerial(const szUsername: string): string;
var i, iSum: Integer;
begin
iSum:= 0;
for i:= 1 to Length(szUsername) do
begin
if Byte(szUsername[i]) <> $20 then
iSum:= iSum + Ord(szUsername[i]);
end; Result:= Format('%s-%d',['SnD', (iSum * $1749) - Length(szUsername)]);end;procedure TForm1.btn1Click(Sender: TObject);
begin edit1.Text:= GenerateSerial(UpperCase('tutsyou'));
end;

Credits to Departure. wink.png

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

EDIT:

Well, I found out why my keygen didn't work. It's because I didn't delete length of username from the sum. Damn how could I forget that. Anyway, here is my work before Departure write hes own:


function TfrmMain.getkey(hName:string):string;
var
i:integer;
c:integer;
re:array of integer;
rC:string;
res:integer;
begin
if Length(hName) > 40 then
begin
lblInfo.Caption := 'Name is too long.';
exit;
end;
if Length(hName) < 2 then
begin
lblInfo.Caption := 'Name is too short.';
exit;
end;
lblInfo.Caption := '-';
hName := UpperCase(hName);
SetLength(re, Length(hName)+2);
for i := 1 to Length(hName) do
begin
re[i] := Byte(hName[i]) * $1749;
res := res + re[i];
Result := Result + IntToStr(re[i]); // debug
end;
Result := 'SnD-' + IntToStr(res-length(hName));
end;
procedure TfrmMain.txtUsernameChange(Sender: TObject);
begin
txtKey.text := GetKey(txtUsername.Text);
end;

The problem was in last line of function (Result). My code was only like:

result := 'SnD-' + IntToStr(res) so my key was not "SnD-1186236" but "SnD-1186239" (6->9). So I had to put it like [code]Result := 'SnD-' + IntToStr(res-length(hName));
Edited by dn5
Link to comment
  • 4 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...