Jump to content

peterthepigeon

Members
  • Posts

    112
  • Joined

  • Last visited

Everything posted by peterthepigeon

  1. Ok so I'm going to be working from Ollydbg here so let's get this party started. I will be using 1.10 initially then we will switch to 2.0, or xdbg. It doesn't matter. First we're going to need to make sure that C&C95 runs in window mode. Once you have done that, startup the game. Now we're going to attach Ollydbg to the game. Start ollydbg. Click attach. Look for C&C95, then attach it to the game. This is what you should see if you're using Ollydbg. Let's focus our attention to the right most pane. The registers pane for the current executing thread. You'll notice there are a number of registers. EAX, ECX, EBX, EDX, ESP, EBP, ESI, EDI, EIP. EAX -> typically used to return the result of a routine, known as the accumulator ECX -> used in loops typically, for certain types of calling conventions ie class methods is used to pass the this pointer, or in the __fastcall calling convention EBX -> arithmetic EDX -> used for arithmetic mainly, but also used in __fastcall calling convention to pass arguments via registers ESP -> stack pointer, holds the current frame pointer EBP -> pointer to the base of the current frame pointer for a routine ESI -> Extended Source Index, used for string operations mainly EDI -> Extended Destination Index, string operations mainly EIP -> Extended Instruction Pointer, holds the pointer to the currently executing instruction. Followed up by your flags and your "segment" registers of ES, CS, SS, DS, FS, GS CS -> Code Segment SS -> Stack Segment DS -> Data Segment ES -> Extra Segment FS -> Far Segment ( in windows we use this to get at the PEB in process ) GS -> Extra Segment or as I call it the Global Segment ( my wording, not Intel/AMD's ) The last error of the thread is right underneath that. Search errorcodes on MSDN if you want to grasp the significance of that. To the right of the segment registers you have a doozy of flags. These are related to your branching instructions. C -> carry flag ( think of addition here ) P -> parity flag ( odd even ) A -> adjust flag ( mainly used for binary coded decimal arithmetic I've hardly ever used this one ) Z -> zero flag, typically set if the two are equal, eg ( a == b ) S -> sign flag ( for jumping if the result was signed ie negative ) T -> trap flag ( for debugging ) D -> direction flag, left to right or right to left for string operations O -> overflow flag ( eg if we overflowed for an arithmetic operation, ie if we had 8 bit registers 127 + 127 = 254, but since we use most significant bit for sign, we have an overflow ) EFL -> Extended Flags We use this for our branching instructions. We'll cover those soon enough. Lastly we have our FPU portion, suffice to say I'm not going to delve into this much right now. Below the registers pane you'll see the stack pane for the current executing thread. 0CE1FF5C 77B1F926 RETURN to ntdll.77B1F926 from ntdll.DbgBreakPoint This represents the top of the stack for the current function frame. Notice it says return, and if you notice in the CPU pane we have RETN instruction. This pops the address stored at the current ESP off the stack into the EIP register and resumes execution. We'll cover this in depth in future posts. I'm going to end it here for now. We'll get started on understanding more soon enough.
  2. Debug time! Wee hee we made it. First things first, we need some tools of the trade. I've grown to love Ollydbg so much, so you can use that or you can use xdbg. Both are fine tools. http://x64dbg.com/#start http://ollydbg.de Both are very much alike so most of what we do easily translates between the two. We'll also need CFF Explorer. http://www.ntcore.com/exsuite.php Next we'll need cheat-engine. Make sure you download the 32 bit version. http://www.cheatengine.org/ You could download a hex-editor, but CFF Explorer already provides that functionality so you don't really have to, but if you want to, there's a number of free ones out there. Lastly, we need IDA. If you don't have access to the commercial version(s), you can use the free IDA 5.0. https://www.hex-rays.com/products/ida/support/download_freeware.shtml This is a very short post because next post we will dig into messing with C&C95. We're going to take a whack at modifying some good stuff. Like making Obelisk of Lights able to shoot down Orcas and A-10, locating other stuff like Super Weapon timers, and so on. All the while you're going to be learning about branches, opcodes, modrms, sibs and the whole nine. We'll also cover threads, handles and so much more.
  3. You need all around knowledge to mod/hack efficiently. Header editting is easy, modify the number of sections in the file header, make sure you aren't going over the size of headers unless you fix it up and then make sure you modify the SizeOfImage ( optional header ) and add your section accordingly. If you should happen to exceed the header size you're going to have to fix those pesky relocations and realign your sections by the file alignment and adjust the virtual address/ raw addresses accordingly. CFF Explorer is the best tool for the job.
  4. So you made it this far? Good. We're going to cover the PEB now, otherwise known as the Process Environment Block. This little doozy of a structure can be located at FS:[0x30] for 32 bit and FS:[0x60] for 64 bit. The Process Environment Block is referenced within the Process Basic Information struct itself. The PEB contains a weatlh of information, such as the loaded images in a doubly linked list called the loader module list, there are 4 linked lists in total, the parameters, session id, if it's being debugged, the pointer to the heap, and much much more. If you want a pretty good idea of the whole scope of the struct I can only recommend you look at the ReactOS source code. If you have any questions feel free to ask. For the sake of simplicity I must end the discussion on the PEB here for now. I will try to delve into it more in the future. Executable images are largely mapped into memory by LoadLibrary. I am going to give you a very brief overview of how this works. First we check to see if we have already loaded this module, if so we just return. If not, we resolve the path to the file on disk. We basically read the whole file in memory and create a section object for it, aligning it to virtual memory. If the image requires base relocation we handle that. Then we check do an import lookup. Once that's done we adjust the protections on the individual regions within the executable. Then we call the module entry point, which can be the TLS and/or the export to say WinMain or main(). The TLS is always called first period. Typically you'll have: DOS/PE Header .text - PAGE_EXECUTE_READ or PAGE_WRITECOPY, or something thereof .bss - uninitialized variables, microsoft visual studio merges this into either the .data or .rdata section .idata - import section .edata - exports .data - all your data which is both readable/writable .reloc - this section contains the rvas and base fixups to apply .rsrc - optional if the executable doesn't have icons, menus, or something like that .etc - you can postpend any number of sections you want up to a limit Executable images loaded by LoadLibrary always have a section object associated with them period. VirtualQuery on the region will show you as MEM_IMAGE. You can retrieve the path to the file on disk by calling GetMappedFileName. You can load an image into memory without invoking LoadLibrary, but you must manage the imports, relocations, tls callbacks, etc manually. This is called manual mapping. You'd use VirtualAlloc to do your dirty work, thus showing up only as MEM_PRIVATE to all VirtualQuery reads. I'm going to finally cover the debugging aspects in the next post, I feel I've covered enough base ground to warrant that. We will have to discuss threads, handles, and other operating system concepts in order to further our education. Clarification: When I speak of images or modules I am referring to the exes / dlls you know and love
  5. Let us continue on the memory road shall we? Why is a page typically defined as 4096 bytes? Well it is largely due to processor architecture, not relating to any choice by any OS developer(s) in particular. I could delve deeper into the why, but that's for another time. If you're still doubly curious, wikipedia has an alright article on the subject. http://en.wikipedia.org/wiki/Page_(computer_memory) We briefly touched on some of the semantics in windows regarding allocations and special cases for the protections. For the record memory allocation types can be broken down into: MEM_IMAGE MEM_PRIVATE MEM_MAPPED The dlls/exes you know and love are typically mapped as MEM_IMAGE. Whereas heap and other data will typically be mapped as MEM_PRIVATE, and MEM_MAPPED is for data views not for executable images. CreateFileMapping anyone? All of the types can be treated as sections, but mostly MEM_IMAGE and MEM_MAPPED are. I won't discuss various nuances here either. I also briefly touched on why you should prefer the heap over using VirtualAlloc citing the allocation granularity. However I will delve a bit more deeply into the why. If you are allocating a few hundred bytes, if you call VirtualAlloc, you are effectively mapping a whole page at 64k grandularity. Whereas if you used the heap through malloc/new/HeapAlloc/RtlAllocateHeap you could avoid allocating a whole new page. Not only that you are also increasing the working set for your process, ergo please use the heap whenever the need arises. Next topic will cover more things, such as the PEB and other undocumented internal structures, along with a brief overview of how executable images are mapped into memory. We'll start to delve into the debugger panes.
  6. Now that we have covered some of the basics we can go on. Let us briefly touch on the memory mode of 32 bit and some basic understanding of OS stuff. We call 32 bit memory model flat memory mode, but technically it is still segmented. In the last posts we touched on the size of a double word which gives you an idea of how much memory you can address in total. When I speak of segmentation you have to understand that I am referring to the seperation between usermode and kernel mode. Usermode resides in the lower half of the 32 bit model. Specifically 0 -> 0x7FFFFFFF, whereas kernel mode resides 0x80000000 -> 0xFFFFFFFF. 16 bit segmentation allows you to address more than 64K of memory. If you still want to know about 16 bit segmentation wikipedia has a good article about it. In windows the allocation granularity is 64k. Generally when you allocate memory it is preferable to use the heap over calling VirtualAlloc for small allocations. I won't touch on 64 bit here, suffice to say for now we're limited to a 48 bit representation as of right now ( if I recall correctly, if this is wrong someone correct me ), which eerily mirrors the issue of 16 bit mode and the need to have more than 1 megabyte of addressable memory. Programs which run in usermode are isolated from one other, and if you modify a core component say kernel32.dll or another, a copy on write mechanism creates a unique copy for that particular process. What does that mean? Typically every process has the same copy of kernel32.dll, it's mapped globally in the same area and shared across all processes typically unless ASLR is used, in which case you can... well that's an advanced topic, CR3 that is and page tables, not for here sadly. At anyrate, if you modify it as I said before a copy on write mechanism creates a unique copy for that process and every other process happily chugs along with the mapped copy shared globally. This is a solution to the issues suffered from windows 98 and below in which you modified kernel32.dll in one process it affected all processes thus allowing for some very nasty usermode viruses. There are some of the memory protection modes available: PAGE_READONLY PAGE_READWRITE PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE PAGE_GUARD PAGE_NOACCESS PAGE_EXECUTE_WRITECOPY PAEG_WRITECOPY For further information please reference: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366786(v=vs.85).aspx Some of these protection constants can only be used by treating the allocation as a section. ( NtCreateSection ) Most debuggers make use of PAGE_GUARD/PAGE_NOACCESS to place memory breakpoints. This works by making an entire PAGE ( 4kb -> 32/64 bit or for more precisely: 4KB (all modes), 4MB (32-bit non-PAE), 2MB (32/64-bit PAE), 1GB (64-bit, always PAE), look up your processor to see exactly. ) marked as either guard/noaccess. When the CPU executes code or reads data or writes to that region the IDT executes the exception handler which calls the usermode code to process the exception generated. I won't discuss SEH/VEH or setting up an exception handler at all. There are other ways to place breakpoints, such as using int3, int1, etc, and of course hardware breakpoints. I won't discuss using more advanced kernel/hypervisior methods as that is way out of the scope of the discussion here. Hardware breakpoints allow us to use debug registers to mark a specific 4 byte ( 32 bit ) or 8 byte ( 64 bit ) piece of memory, it could be code, or data to be triggered on read, write, or execute or some combination thereof. You have a total of 4 breakpoints to work with here. As for int3, etc, you simply modify the byte in the target area you want to hook and use your exception handler to redirect code flow to where you want. I know I promised I would discuss the debugger panes, but as you have to realize there is a lot of ground we have to cover before we can even screw around with IDA, Ollydbg, CheatEngine, xdebugger, etc.
  7. I know they're not that's why I said wavelength in the first post the usage of the word rainbow was just to paint a picture in the mind. Unintended superweapon effects? Nope, fully intended. An impromptu harvest of that precious x-ray tiberium creates a demo truck except it's singleplayer strength nuke. For the record visceroid should be modded to nyan cat, and spawn a whole rainbow of tiberium in his wake while destroying everything.
  8. I haven't given too much thought to explosives. I want bigger bangs the more potent the tiberium is naturally. I almost wonder if making harvesters explosive if they're carrying enough tiberium of a certain purity would be fun. For instance you harvest some of that super precious x-ray tiberium and drive it straight into an enemy base. They blow up the harvester causing it to detonate like it's a nuke. Which leads to more ideas.
  9. Not in the current iteration no. As far as hacking work, not even that much, I've already located the tiberium growth function, know how to modify the bailcounts and value of harvested tiberium. Adding mineral content means a byte variable or something to each cell, which either there may be an unused var to align to memory to it means allocating whole new array of cells size 0x22. Locating all references is easy as I have written a tool to do exactly that. Representing the depletion of the land is either changing tiles or adding smudges a bit more work than everything else so far, but doable. The coloration idea is also simple to do as well.
  10. Instead of a visceroid, nyan cat pops out leveling everything in his wake and leaving a trail of nyan tiberium! In all seriousness, the repleshiment of the mineral content would always be less than the total sum. I'm not entirely sure it would aid turtling, since you trade a risk that you wait for the field to mature, assuming there is sufficient mineral content to carry it to higher forms of tiberum whilst trying not to harvest too much. If of course the enemy sucks your fields dry and there is no mineral content left, no more tiberium can spawn unless otherwise noted.
  11. Since Tiberian Sun arrived on the scene there have been at least 2 varieties of tiberium. What if we had a rainbow of tiberium? Afterall, this appears to be the intent Westwood was working with. All the way from say microwave tiberium to x-ray? For example microwave tiberium would be nearly colorless and nearly worthless, and practically harmless, but spread like wildfire. On the flipside as you approach X-Ray tiberum, the growth rate slows down, but it becomes more and more explosive and far more valuable. The soil leached bare, the plants dead from radiation or mutated. Any unprotected infantry traversing through the higher grades would be more likely to mutate into visceroids or die from the radiation. X-Ray tiberium would be practically instantly lethal to any infantry even chemical warriors and damage lighter vehicles like humvees and such. An economic metric could be each "wavelength" increase nets a somewhat exponential growth in value, depending on the leached minerals. We still keep the bailcount to 28, or perhaps harvesting higher grades of tiberium is so risky, that they reduce the remaining bailcount to ensure safe transport, whereas we can harvest a whole field of lower quality tiberium safely. With respect to the growth and spread of the tiberium as it grows it leaches "minerals" from the soil, meaning that as the game progresses, the value of the tiberium regrowth progressively decreases asymptotically to 0, or for simple terms, instead of that green field you were harvesting, it regrows as yellow tiberium, then orange and so on. I would hope we can modify the engine to gradually replace the green grass with dead desert soil representing the depletion of the land. ( smudge? ) Another portion relating to the growth is that in mineral rich cells, the longer the tiberium remains unharvested, the more it leaches out and the value increases, so a green field would evolve into a blue field of tiberium with enough time, and if enough time passes it could grow into highly valuable x-ray tiberium. Mineral content in the soil can be replenished by destroying units/structures. value = tiberium_type * ( 3 ^ leached_scalar ); where the leached_scalar is in direct proportion to the mineral content of the cell. Thoughts?
  12. Continuing on: Now we at least have some understanding right? Do you know your fundamental binary logic gates? There are 7 types of logic gates which produce meaningful usable output, the remainder, 9, are essentially gibberish. They are as follows: AND, OR, NOT, XOR, NAND, NOR, XNOR. NAND and NOR are considered universal logic gates and can be used to construct all the other logic gates. Why in the world am I talking about logic gates? Simple answer, bitwise operations and of course logical operators. Your bitwise operators are as follows in C/C++: NOT: ~ OR: | AND: & XOR: ^ Your logical operators are: NOT: ! OR: || AND: && XOR: != To construct the NAND, NOR and XNOR we must mix up our operators and use parenthesis where necessary. Bitwise: NAND: ~( a & b ) NOR ~( a | b ) XNOR ~( a ^ b ) Logical: NAND: !( a && b ) NOR: !( a || b ) XNOR !( a != b ), alternatively... ( a == b ) Next we'll go over our truth tables, a nice introduction to digital logic. NOT: 0 -> 1 1 -> 0 AND 0 AND 0 -> 0 1 AND 0 -> 0 0 AND 1 -> 0 1 AND 1 -> 1 OR 0 OR 0 -> 0 1 OR 0 -> 1 0 OR 1 -> 1 1 OR 1 -> 1 XOR 0 XOR 0 -> 0 1 XOR 0 -> 1 0 XOR 1 -> 1 1 XOR 1 -> 0 NAND 0 NAND 0 -> 1 1 NAND 0 -> 1 0 NAND 1 -> 1 1 NAND 1 -> 0 NOR 0 OR 0 -> 1 1 OR 0 -> 0 0 OR 1 -> 0 1 OR 1 -> 0 XNOR 0 XNOR 0 -> 1 1 XNOR 0 -> 0 0 XNOR 1 -> 0 1 XNOR 1 -> 1 A little sidenote, the XOR operation is used to implement addition for all binary adders, which arguably is the most important operation in all math. You can't do subtraction efficiently without it, or division or multiplication. The AND gate is used to check for a carry. Our next topic will cover the basics of disassembly, namely understanding what you see in some of the debugger panes. This is precisely why we covered these topics.
  13. So you want to mod/hack C&C95, or perhaps RA1, or another game? You've been studying those C/C++ tutorials and you think you have a pretty good grasp of the material right? You know how to overload operators, why binary_search is so cool, making use of templated classes, and those pesky pointers and references. All of that is second nature to you right? I also hope you're at least familiar with algebra. However, you have no clue where to start. Well this tutorial is designed to get your feet wet. First I must stress that before we start disassembling streams of instructions, whacking those modrms and sibs into submission, relocating code blocks, enlarging sections, prepending prefixes we have to start with a basic understanding of terminology. We'll start with the lowly bit. A bit is defined as a single number, either 1 or 0. The basis of binary. Bitwise operations operate on bits obviously. Remember your bitwise operators from C/C++? I hope so. Because we're going to need them when extracting registers from the modrm/sib. Among other things including the scaling and what type of operation it is, whether it's a register or memory operation. Hence the name MODRM and SIB ( scaled index byte ) Moving on we move to the next division, called the nibble. A nibble is defined as 4 bits. Each additional bit allows us to represent more numbers. So whereas a single bit represents 1 number, 0 or 1, a nibble can represent 16 numbers, specifically 0-15. Remember, when we're in computer land we always start at 0. So for instance: 0101, represents the decimal number 5. Why? Because converting from binary to decimal requires us to represent each place as a power of 2. 8 4 2 1 0 1 0 1 Clear I hope. Next, the absolute lowest level division in terms of memory/code representation computers is the byte. Granted using bitwise operations we can manipulate the nibbles and individual bits, but that's for another time. This is the smallest representation in a modern computer. Think those bools in your C/C++ program are bits? Wrong, they're actually bytes. A byte is composed of 8 bits, or 2 nibbles and can effectively represent 0-255. After that we move to the word, or 16 bits, or 4 nibbles or 2 bytes, which can represent 0-65,535. Then the double word, 32 bits, 8 nibbles, 4 bytes, 2 words, which can represent 0-4,294,967,295. Then the quad word, 64 bits, 16 nibbles, 8 bytes, 2 dwords, 4 words. We can change the sign of a byte, word, dword, or qword ( oword - 128 bits, 32 nibbles, 16 bytes, 4 dwords, 8 words ) by adjusting the most significant bit. How do we do that? We set the most significant bit to either 0 or 1. The most significant bit is the left most bit, and we thus set it to 1. This changes our sign to negative. Normally when you compile code if you want it to be interpreted as unsigned you must specify in the variable's declaration. ( I really hope you remembered that and sang along with me ) In the case of a byte it would be bit 8 ( counting right from left ), or 128 ( 2^7 ) in this case. 128 64 32 16 8 4 2 1 1 0 0 0 0 0 0 1 Which would be -127. 128 64 32 16 8 4 2 1 0 1 1 1 1 1 1 1 Which would be 127. Notice a pattern? We have to use invert all the bits and add 1 to get the negative representation of a positive number and likewise. Thus I must conclude it here for the time being.
  14. A harvester holds 28 bails of tiberium. Each bail for the human player is worth 25 credits whereas for the computer it is worth 708 credits.
  15. Even so, a well written neural network pattern searching tool would find it. If that's a bother, I can only recommend using hardware breakpoints and notating all faulting addresses. You are subject to possibly missing instances of the macro entirely if they don't access the memory location. I.E. they only are called when a certain trigger is caused or situation.
  16. There are several ways I could point you to without giving code as to how to find all occurrences of a particular macro. But firstly, you need to obtain the size of the code section and so on. This is just reading the sections. Then you will need a length disassembly engine. You'll notice your displacements for edx is 0x28 and 0x2C respectively and the immediate value is 0x40. You have several choices from here on out: 1) Employ a neural network like solution. It could be an adaline network, hopfield, bi-directional associative memory, and so on. You'll want to realize that you are matching based on the similarity of the appearance of the code. 2) Do a behavior based search, that is you define the behavior of the opcodes you are searching for and your pattern matcher only returns streams of opcodes that match the defined behavior. 3) 1 & 2. Preferably. 4) Standard find pattern with wildcards and so on. 5) Some other stuff here
  17. Utterly trivial to do a detour on the code and check the sounds. As far as pathfinding is concerned we'd have to reverse engineer the existing data structures and learn how to interpret the data correctly. So that we could apply a better path finding algorithim as opposed to what is in the code now.
  18. Thing is, reverse engineering is a bunch of intuition and deductive reasoning. Disassemblers, decompilers, debuggers and process/memory searching tools can simply the task such that a highly experienced person can tear apart a binary quickly.
  19. Interesting, guess I'll take a look at that too
  20. I found the tiberium spread to new cells code. However I've yet to find how to increase the growth rate, short of setting speed to super fast.
  21. Blossom Tree animation: 004B3E70 8066 22 EF AND BYTE PTR DS:[ESI+22],0EF 004B3E74 C647 02 00 MOV BYTE PTR DS:[EDI+2],0 004B3E78 8A47 02 MOV AL,BYTE PTR DS:[EDI+2] 004B3E7B 8847 03 MOV BYTE PTR DS:[EDI+3],AL This resets the cycle. 004B3ED1 8847 02 MOV BYTE PTR DS:[EDI+2],AL 004B3ED4 8847 03 MOV BYTE PTR DS:[EDI+3],AL This starts the animation cycle. 004B3E6E 74 67 JE SHORT C&C95.004B3ED7 Byte patching this to an unconditional jump or like behavior causes the Blossom Tree to continue animating without stopping. 004AC820 . 68 60AD5000 PUSH C&C95.0050AD60 004AC825 . 68 0AAD5000 PUSH C&C95.0050AD0A 004AC82A . 6A 01 PUSH 1 004AC82C . 68 58020000 PUSH 258 004AC831 . 68 7B020000 PUSH 27B 004AC836 . 68 CC844F00 PUSH C&C95.004F84CC ; ASCII "SPLIT2" 004AC83B 6A 01 PUSH 1 ; m_bIsInvulnerable 004AC83D . 6A 01 PUSH 1 004AC83F . 6A 00 PUSH 0 004AC841 . 6A 00 PUSH 0 004AC843 . 6A 00 PUSH 0 004AC845 . 6A 00 PUSH 0 004AC847 . 6A 01 PUSH 1 004AC849 . 6A 00 PUSH 0 004AC84B . B9 C000D501 MOV ECX,1D500C0 004AC850 . BB 1C000000 MOV EBX,1C 004AC855 . 6A 01 PUSH 1 004AC857 . BA 12000000 MOV EDX,12 004AC85C . B8 48185600 MOV EAX,C&C95.00561848 ; ASCII "SPLIT2" 004AC861 . E8 6E030000 CALL C&C95.004ACBD4 004AC866 . 68 60AD5000 PUSH C&C95.0050AD60 004AC86B . 68 0AAD5000 PUSH C&C95.0050AD0A 004AC870 . 6A 01 PUSH 1 004AC872 . 68 58020000 PUSH 258 004AC877 . 68 7B020000 PUSH 27B 004AC87C . 68 D3844F00 PUSH C&C95.004F84D3 ; ASCII "SPLIT3" 004AC881 6A 01 PUSH 1 ; m_bIsInvulnerable 004AC883 . 6A 01 PUSH 1 004AC885 . 6A 00 PUSH 0 004AC887 . 6A 00 PUSH 0 004AC889 . 6A 00 PUSH 0 004AC88B . 6A 00 PUSH 0 004AC88D . 6A 01 PUSH 1 004AC88F . 6A 00 PUSH 0 004AC891 . B9 C000D501 MOV ECX,1D500C0 004AC896 . BB 1D000000 MOV EBX,1D 004AC89B . 6A 01 PUSH 1 004AC89D . BA 13000000 MOV EDX,13 004AC8A2 . B8 7C185600 MOV EAX,C&C95.0056187C ; ASCII "SPLIT3" 004AC8A7 . E8 28030000 CALL C&C95.004ACBD4 Called at startup of game, for Blossom Tree stuff.
  22. np happy to take some load off your shoulders Going to take a look at tiberium spawning logic now. Blossom tree is sorta whatever because it would likely fall in with buildings and they're already documented by some cnc editors.
  23. Found it Nyerguds: 004398CB E8 D02A0100 CALL C&C95.0044C3A0 Spawn function: 0044C68E BA 01000000 MOV EDX,1 0044C693 E8 B0CD0400 CALL C&C95.00499448 Notice EDX. That's the index into the string table for unit names. EDX is moved into EAX. 0049945A |. 8B0485 38045000 MOV EAX,DWORD PTR DS:[EAX*4+500438] ; C&C95.00530018 Now we have the unit name to reinforce/spawn, etc. You to adjust the buildlevel to spawn more than 1 A-10, ORCA, etc, not the number of aircraft spawned. 0044C637 BB 03000000 MOV EBX,3 0044C63C A1 10525000 MOV EAX,DWORD PTR DS:[505210] 0044C641 31D2 XOR EDX,EDX 0044C643 F7F3 DIV EBX 0044C645 89D9 MOV ECX,EBX 0044C647 EB 16 JMP SHORT C&C95.0044C65F 0044C649 A1 64525000 MOV EAX,DWORD PTR DS:[505264] 0044C64E 89C2 MOV EDX,EAX 0044C650 BB 05000000 MOV EBX,5 0044C655 C1FA 1F SAR EDX,1F 0044C658 F7FB IDIV EBX 0044C65A B9 03000000 MOV ECX,3 0044C65F BB 01000000 MOV EBX,1 0044C664 39CB CMP EBX,ECX 0044C666 7C 02 JL SHORT C&C95.0044C66A 0044C668 87CB XCHG EBX,ECX 0044C66A 39D8 CMP EAX,EBX 0044C66C 7F 02 JG SHORT C&C95.0044C670 0044C66E 89D8 MOV EAX,EBX 0044C670 39C8 CMP EAX,ECX 0044C672 7C 02 JL SHORT C&C95.0044C676 This is the build level stuff. This helps to control how many units are spawned, in addition what's below. 004994CA |. 8A86 2A010000 |MOV AL,BYTE PTR DS:[ESI+12A] 004994D0 |. 3C 03 |CMP AL,3 004994D2 |.^77 EE |JA SHORT C&C95.004994C2 ESI+12A = number of aircraft to spawn, limited to 3.
  24. Think I found the spawning function. 004108F8 . 53 PUSH EBX 004108F9 . 51 PUSH ECX 004108FA . 89C1 MOV ECX,EAX 004108FC . B8 B2000000 MOV EAX,0B2 00410901 . E8 7E2C0000 CALL C&C95.00413584 00410906 . 85C0 TEST EAX,EAX 00410908 . 74 10 JE SHORT C&C95.0041091A 0041090A . 8B1A MOV EBX,DWORD PTR DS:[EDX] 0041090C . 8B51 48 MOV EDX,DWORD PTR DS:[ECX+48] 0041090F . 0FBE1B MOVSX EBX,BYTE PTR DS:[EBX] 00410912 . C1FA 18 SAR EDX,18 00410915 . E8 9E2C0000 CALL C&C95.004135B8 0041091A > 59 POP ECX ; C&C95.00530018 0041091B . 5B POP EBX 0041091C . C3 RETN 00410915 . E8 9E2C0000 CALL C&C95.004135B8 When you trigger A-10. Check EDX. I've gotten it to spawn A-10 and Cargo plane, A-10 and orca, 3 orcas, cargo plane, etc.
  25. Well it's called right after you select a target to bomb, so it gets us closer to the range where we can find out how the game chooses how many A-10s to spawn.
×
×
  • Create New...