Tuts 4 You

Delphi; Help with string multiplication

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 EBP004012C8  |.  8BEC          MOV EBP,ESP004012CA  |.  68 96334000   PUSH keygenMe.00403396               	; /StringOrChar = "DN5"004012CF  |.  E8 8A000000   CALL <JMP.&user32.CharUpperA>            ; \Uppercase every char in username004012D4  |.  FF75 08   	PUSH DWORD PTR SS:[EBP+8]                ; /-> String: DN5 (into EAX)004012D7  |.  E8 D6000000   CALL <JMP.&kernel32.lstrlenA>            ; \lstrlenA004012DC  |.  8BD0          MOV EDX,EAX  ;  EDX = EAX ('N5')004012DE  |.  85D2          TEST EDX,EDX  ;  EDX = Number of username characters004012E0  |.  7E 6D     	JLE SHORT keygenMe.0040134F  ;  Jump if lower username character is lower then 3004012E2  |.  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 d32004012F4  |.  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 EAX00401301  |.  03F0          |ADD ESI,EAX                         	;  Add EAX to ESI00401303  |>  41            |INC ECX                             	;  Increment ECX00401304  |.  4A            |DEC EDX                             	;  ...and decrement EDX00401305  |.^ 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,ESI0040130F  |.  50            PUSH EAX                             	; /<%d>00401310  |.  68 1F364000   PUSH keygenMe.0040361F               	; |Format = "%d"00401315  |.  52            PUSH EDX                             	; |s => keygenMe.004034D600401316  |.  E8 3D000000   CALL <JMP.&user32.wsprintfA>         	; \wsprintfA0040131B  |.  83C4 0C   	ADD ESP,0C                           	;  Add h0C (12) into ESP0040131E  |.  68 1A364000   PUSH keygenMe.0040361A               	; /String2 = "SnD-"00401323  |.  68 56324000   PUSH keygenMe.00403256               	; |String1 = keygenMe.0040325600401328  |.  E8 7F000000   CALL <JMP.&kernel32.lstrcpyA>            ; \lstrcpyA0040132D  |.  68 D6344000   PUSH keygenMe.004034D6               	; /StringToAdd = "1186236"00401332  |.  68 56324000   PUSH keygenMe.00403256               	; |ConcatString = "SnD-1186236"00401337  |.  E8 64000000   CALL <JMP.&kernel32.lstrcatA>            ; \lstrcatA0040133C  |.  68 56324000   PUSH keygenMe.00403256               	; /String2 = "SnD-1186236"00401341  |.  68 16314000   PUSH keygenMe.00403116               	; |String1 = "SnD-1186236"00401346  |.  E8 5B000000   CALL <JMP.&kernel32.lstrcmpA>            ; \lstrcmpA0040134B  |.  C9            LEAVE0040134C  |.  C2 0400   	RETN 40040134F  |>  B8 01000000   MOV EAX,100401354  |.  C9            LEAVE00401355  \.  C2 0400   	RETN 4`

Here is the final result of phished serial.

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.

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.

Hello dn5, this should be a more efficient code for your last example:

`sum := (Byte('D') + Byte('N') + Byte('5')) * \$1749;`

@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.

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

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;beginif Length(hName) > 40 thenbegin  lblInfo.Caption := 'Name is too long.';  exit;end;if Length(hName) < 2 thenbegin  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);begintxtKey.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
• 4 weeks later...

how to find edit box of delphi program?