Heroes of Might and Magic Community
visiting hero! Register | Today's Posts | Games | Search! | FAQ/Rules | AvatarList | MemberList | Profile


Age of Heroes Headlines:  
5 Oct 2016: Heroes VII development comes to an end.. - read more
6 Aug 2016: Troubled Heroes VII Expansion Release - read more
26 Apr 2016: Heroes VII XPack - Trial by Fire - Coming out in June! - read more
17 Apr 2016: Global Alternative Creatures MOD for H7 after 1.8 Patch! - read more
7 Mar 2016: Romero launches a Piano Sonata Album Kickstarter! - read more
19 Feb 2016: Heroes 5.5 RC6, Heroes VII patch 1.7 are out! - read more
13 Jan 2016: Horn of the Abyss 1.4 Available for Download! - read more
17 Dec 2015: Heroes 5.5 update, 1.6 out for H7 - read more
23 Nov 2015: H7 1.4 & 1.5 patches Released - read more
31 Oct 2015: First H7 patches are out, End of DoC development - read more
5 Oct 2016: Heroes VII development comes to an end.. - read more
[X] Remove Ads
LOGIN:     Username:     Password:         [ Register ]
HOMM1: info forum | HOMM2: info forum | HOMM3: info mods forum | HOMM4: info CTG forum | HOMM5: info mods forum | MMH6: wiki forum | MMH7: wiki forum
Heroes Community > Heroes 3.5 - WoG and Beyond > Thread: Heroes 3 Hacking Reference Guide
Thread: Heroes 3 Hacking Reference Guide This thread is 42 pages long: 1 10 20 30 ... 31 32 33 34 35 ... 40 42 · «PREV / NEXT»
BTB
BTB


Famous Hero
Moist & Creamy
posted November 01, 2022 12:39 PM

Are you trying to give Orrin an Archer specialty or a specialty in the Archery skill?

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 01, 2022 01:48 PM

Hi BTB,

I try to use the modification described here:

...
Assuming we want to go with a 1% bonus per level, we'll need to create a 0.01 floating point value for
our DWORD pointer since one doesn't already exist anywhere in the code. Simply put, a DWORD pointer is
just an address to somewhere else in the code that's written backwards (E4 EA 63 00 = 63EAE4, or 23EAE4
in a hex editor), and in this case what it's expecting to find there is a floating point value (like the
percentages we use in the skill table above). The good news is that there's no real restrictions as to
where this needs to be - we can point to literally anywhere in the code where the desired value exists,
including the skill table itself if we really want to. By far the easiest solution, however, is to just
use the 6 bytes of space we free up by removing the second command above.

Rather than 90 90 90 90 90 90, let's instead replace the ADD with EB 04 0A D7 23 3C. The 0A D7 23 3C is
our floating point value, while the EB 04 means "don't process the next 4 bytes" since it's not actually
an instruction and the game would crash if it tried to interpret it as such. We can then reference this
value by taking the address and converting it to a DWORD pointer, as seen on the table below.

Skill Bonus%  ADD -> NOP  (DWORD PTR)  4D -> 45
-----------------------------------------------------------
Archery 0E4420    0E4424   (26 44 4E 00)  0E442B
...

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 01, 2022 04:00 PM

Hi BTB,

dumb me forgot to mention where i place my changes...
004E442        02444E400EB040000447AD845

resulting in:
Heroes3 HD.exe+E4420 - 24 44                 - and al,44 { 68 }
Heroes3 HD.exe+E4422 - E4 00                 - in al,00 { 0 }
Heroes3 HD.exe+E4424 - EB 04                 - jmp "Heroes3 HD.exe"+E442A { ->Heroes3 HD.exe+E442A }
Heroes3 HD.exe+E4426 - 00 00                 - add [eax],al
Heroes3 HD.exe+E4428 - 44                    - inc esp
Heroes3 HD.exe+E4429 - 7A D8                 - jp "Heroes3 HD.exe"+E4403 { ->Heroes3 HD.exe+E4403 }
Heroes3 HD.exe+E442B - 45                    - inc ebp
Heroes3 HD.exe+E442C - FC                    - cld

Best wishes

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 01, 2022 04:48 PM

Obviously, you are doing something wrong. You can see it from those inappropriate assembler instructions.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 01, 2022 05:23 PM

Hi AlexSpl,

yes indeed, Godzilla got a stroke trying to read this as assembler code . I'm sure BTB's info and instructions are correct. I might not understand them fully. Here with my own words:
1. The changes take place at the address given in the column "Bonus%".
2. At the address you have to write the address, where the float value is located. See point 4.
3. Because we dont add 1 to the calculated value we take these 6 bytes to first ad EB 04 as jump information.
4. The next 4 bytes are the float value.
5. For addition of this value instead of multiplying we write D8 45 instead of D8 4D.

When I look at the unchanged Bytes of Armorer (0E45C9 + 400000) The code is like:
Heroes3 HD.exe+E45C7 - D8 0D E4EA6300        - fmul dword ptr ["Heroes3 HD.exe"+23EAE4] { (0,05) }
Heroes3 HD.exe+E45CD - D8 05 E0B66300        - fadd dword ptr ["Heroes3 HD.exe"+23B6E0] { (1,00) }
Heroes3 HD.exe+E45D3 - D8 4D FC              - fmul dword ptr [ebp-04]
Heroes3 HD.exe+E45D6 - D9 5D FC              - fstp dword ptr [ebp-04]

Here it starts in the middle of an instruction. The byte row looks the same in E483C + 400000 showing the code of Diplomacy.

So I think there is a problem regarding point 1 and 2 of my interpretation.

Best wishes

Parascus

____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
BTB
BTB


Famous Hero
Moist & Creamy
posted November 01, 2022 05:33 PM
Edited by BTB at 17:37, 01 Nov 2022.

Ok, I see what happened. Those instructions probably aren't very clear.

At 0E4424, you write EB 04 0A D7 23 3C
At 0E4420, you write 26 44 4E 00

More specifically, we have this instruction:

0E441E - D8 0D E4EA6300 - fmul dword ptr [0063EAE4] { (0.05) }

The change at 0E4420 changes that DWORD pointer to 4E4426, where the new floating point value is located.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 11:45 AM

Hi BTB,

now it is working ... more or less No crashes anymore.

But I'm not sure about the effect :-| I have a test map with Orrin and Uland. Both have Archery skill and in the beignning the same Primary skills. The both have 100 Archers. Orrin has the Archery speciality, adding 10.0 (0A000000 at E4426) percent points to the archery skill per level (using the modifications).

On the map each hero has 10 Dwarfs in front of them followed by 3 trees of knowledge for leveling. At the end there is another pack of 10 Dwarves.

Orrin is making 97-146 damage points (displayed in the status bar and after leveling (to 2/1/1/1 on level 4) 105-157 points.
Uland makes 112-168 damage and after leveling (to 0/2/1/1) still 112-168.

I wonder why Orrin makes less damage than Uland and I thought it would rise to a much higher damage (3 levels * 10% = 30%).

Any thoughts?

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
BTB
BTB


Famous Hero
Moist & Creamy
posted November 02, 2022 12:29 PM

For 10%, you need cdcccc3d. Remember that these are floating values.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 02, 2022 12:40 PM

0xA is 1.4013e-44

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 02:02 PM

Hi all,

ah yes, thanks. It has to be a float number, not an integer.

Another reason I found for no good functioning is that in the program I used:
  PI->WriteDword(baseAddress + skillSpecialityAddress + 6, percentage);
instead of
  PI->WriteDword(baseAddress + skillSpecialityAddress + 6, (int&percentage);

So it took the address of percentage instead of the value of percentage ... :-( dumb mistakes done by the easy minded.

Thank you once more.

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
BTB
BTB


Famous Hero
Moist & Creamy
posted November 02, 2022 05:11 PM

Got my fifth-level Castle Guild done now, too:

https://cdn.discordapp.com/attachments/692895170722660434/1037398160546471996/castle.jpg

https://cdn.discordapp.com/attachments/692895170722660434/1037398160835891220/castle2.jpg

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 08:02 PM

Nice!
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 08:18 PM

Oh man, why can't I just understand these mechanics and logics?

I try to use the health buff of the document described in chapter ... & First Aid:
------ -------------------------------------------------------------------------
0E671D ; FIRST AID HEALTH BUFFS
------ -------------------------------------------------------------------------
E8 56E1FFFF call 4E4878 ; -> free space (Diplomacy artifacts)
5F pop edi ; (displaced code)

--------- -------------------------------------------------------------------------
0E4878~A2 ; (EXPANDED SPACE - OVERWRITES DIPLOMACY ARTIFACTS)
--------- -------------------------------------------------------------------------
B9 B8036700 mov ecx,6703B8 ; ECX = unit data index
8A 44 39 10 mov al,[ecx+edi+10] ; EAX = unit data (byte 17)
C0 E8 04 shr al,04 ; shift to "living" flag
A8 01 test al,01 ; alive?
74 15 je 4E489D ; if no -> (displaced code)

8A 44 39 04 mov al,[ecx+edi+04] ; EAX = unit's level (0~6)
40 inc eax ; EAX +1
8B 4D FC mov ecx,[ebp-04] ; ECX = hero
50 push eax ; store EAX
8A 81 E4000000 mov al,[ecx+E4] ; EAX = First Aid skill
59 pop ecx ; ECX = unit's level (0~6 +1)
0FAF C1 imul eax,ecx ; EAX * ECX
01 C3 add ebx,eax ; add EAX to total health bonus (EBX)
8B 46 4C mov eax,[esi+4C] ; (displaced code)
01 D8 add eax,ebx ; ""
C3 ret ; return (0E48A3~926 is free space)

Why do I have problems doing the hook here? It seems simple. As I understand, BTB is inserting a call to 4E4878 to an on code overwriting diplomace artifacts. Because I want to keep those artifacts I try to combine the best of both worlds, BTB's magic status healing first aid tent and additionally for heroes with first aid speciality a health buff on the one hand. On the other hand I want to call my own routine for not using any space of the original game (I know I'm stubborn on this but we love diplomacy).

My thoughts are: Instead of calling the subroutine at 4E4878 I define a hook calling my own implementation. There I set the return address to 4E6722, what should be the next instruction after the call of the subroutine (pop edi). At this moment my program is:

       _PI->WriteLoHook(0x4E671D, executeFirstAidHealthBuff);

and

       int __stdcall executeFirstAidHealthBuff(LoHook* h, HookContext* c) {
           c->return_address = 0x004E6722;

           return NO_EXEC_DEFAULT;
       }

As stubbern as myself the program keeps crashing. Am I so much out of it? Where do I think the wrong way?

Have a nice evening

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 02, 2022 08:24 PM

The address of the next instruction is 0x4E6720, not 0x4E6722.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 08:33 PM
Edited by Parascus at 20:35, 02 Nov 2022.

What?

0E671D: E8 call
0E671E: 56  "
0E671F: E1  "
0E6720: FF  "
0E6721: FF  "
0E6722: 5F pop edi

If this is not correct, how do I count?

Hopeful regards

Parascus

P.S.: Just tried the same with 4E6720 but with the same result, this time crashinig at 4E6721.
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 02, 2022 08:38 PM

A hook takes 5 bytes to write a starting jump. You replace mov eax, [esi+4Ch] with it, and this instruction is only 3 bytes long. You don't need to count addresses manually. Just open IDA and go (G) to 0x4E671D.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 02, 2022 08:53 PM
Edited by AlexSpl at 21:28, 02 Nov 2022.

Quote:
P.S.: Just tried the same with 4E6720 but with the same result, this time crashinig at 4E6721.

This is because you return inside your own hook's starting jump (its size is 5 bytes). The closest safe address is 0x4E6723.

* * *
Let us look into it deeper. Look at

.text:004E671D 024 mov     eax, [esi+4Ch]   ; 3 bytes
.text:004E6720 024 pop     edi              ; 1 byte
.text:004E6721 020 add     eax, ebx         ; 2 bytes
.text:004E6723 020 mov     [esi+4Ch], eax


You place your hook at 0x4E671D, its starting jump requires 5 bytes of space, so you wipe the first 3 instructions with your hook's starting jump (3 bytes + 1 byte + 1 byte of the third instruction). You cannot return inside your hook's starting jump, so the next address you can safely return to is 0x4E6723.

Then you do some job inside your hook's body and return. You may, for example, calculate something and place a result into c->eax, but don't forget that you wiped pop edi, so don't forget to include this wiped instruction into your hook's body: c->edi = c->Pop();

But, most of the time you just choose a better place for your hook For example, why don't you want to place your hook at 0x4E6723 and return EXEC_DEFAULT?

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 10:41 PM

Ah, ok. My mistake was to look at the modified code instead of the original one. Thanks for the hint with (G).

So the process is to insert a hook, which is really overwriting code, to call my own function and to prevent the execution of mov eax, [esi+4Ch] in this case. I asume this is where the health is originally taken from. It is the same as in BTBs code at the 3rd last line. Afterwards the calculated ebx is added and than it returns after the calling instruction.

So I changed my code to:
   _PI->WriteLoHook(0x4E671D, executeFirstAidHealthBuff);
and
   int __stdcall executeFirstAidHealthBuff(LoHook* h, HookContext* c) {
       c->eax = 0x11;

       c->return_address = 0x004E6723;

       c->edi = c->Pop();

       return NO_EXEC_DEFAULT;
   }

IDA is really a good deal at this point, allthough I won't say that I totally understand what is going on. Thanks for all the help and have a good night.

Best regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
AlexSpl
AlexSpl


Responsible
Supreme Hero
posted November 02, 2022 10:53 PM

Btw, your code is equivalent to this simpler one:

int __stdcall executeFirstAidHealthBuff(LoHook* h, HookContext* c)
{
  c->eax = 0x11;
 
  return EXEC_DEFAULT;
}
 
// ...
 
_PI->WriteLoHook(0x4E6723, executeFirstAidHealthBuff);


Mind that by returning EXEC_DEFAULT you tell the patcher to execute all instructions wiped with a hook's starting jump after it's done with your hook body.

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Parascus
Parascus


Adventuring Hero
posted November 02, 2022 11:13 PM

Hi,

so it is overwriting the 5 bytes but stores them at another place to execute them with EXEC_DEFAULT? But than also the eax is overwritten with [esi+4Ch] but I want to return the health in eax, isn't it?

And would having the hook at 0x4E6723 change the health in advance and I ould than handle the already changed health?

Best Regards

Parascus
____________

 Send Instant Message | Send E-Mail | View Profile | Quote Reply | Link
Jump To: « Prev Thread . . . Next Thread » This thread is 42 pages long: 1 10 20 30 ... 31 32 33 34 35 ... 40 42 · «PREV / NEXT»
Post New Poll    Post New Topic    Post New Reply

Page compiled in 0.0911 seconds