@echo off
date /t >> shellexecutea_log.txt
time /t >> shellexecutea_log.txt
echo %* >> shellexecutea_log.txt
I/O in assembly is a matter of calling the appropriate library and kernel functions, no?
Edit: found a better call below, though ShellExecuteA is still interesting.
terranx.exe has a likely I/O call baked in via an external call to ShellExecuteA (https://support.microsoft.com/kb/170918) in shell32.dll.
ShellExecuteA takes a bunch of parameters including the path to a file. It then asks windows to either print the file back or open that file with whatever windows deems best. This almost certainly means that you can use it to call external .exe or .bat files.
In the existing code, the path to open is a URL eastore or alphacentauri.com and shell32 presumably invokes the default browser with it. Maybe it's code left over from the Demo?
Anyway, there's an example in the code at 0052476C. I don't know where that gets called from in the game at the moment, but you can presumably get some part of the code you control to call it. Then all you need to do is change the value of the address that currently reads "http:\\\\www.alphacentauri.com" to "test.bat" and see what happens.
An example test.bat to put in the same directory as terranx.exe might be:Code: [Select]@echo off
date /t >> shellexecutea_log.txt
time /t >> shellexecutea_log.txt
echo %* >> shellexecutea_log.txt
If that works, then we just need to make a wee subroutine that'll take a movie name and pass it to a batch file. That's presumably just a matter of hijacking whichever bit of code currently opens movies.
If that works, then there are only a few more low hurdles to pass.
I think it's worth a try.
The assembly to do this isn't so hard, but I don't know how to edit these binaries. What's your workflow?
* Do you disassemble, edit assembly code and then re-assemble? (Doesn't look like it)
* Do you disassemble, find the code you want to change and then edit in a hex editor?
* Do you do something else?
Edit: Saw your post (http://alphacentauri2.info/index.php?topic=8440.msg47950#msg47950) in the yitzi2.5g thread. Could you go into a little more detail about the process of adding a new alphax.txt variable for me?
play_video:
; Subroutine prologue
push ebp ; Store the caller's base pointer for later.
mov ebp, esp ; Replace base pointer with stack pointer for easier
; calls.
push ebx ; Store caller's registers we might use
push edi
push esi
; Subroutine body
; Accept one parameter, concatenate it with a constant string and pass
; to WinExec.
; Need a large buffer for string concatenation. Longest original movie
; name is 20 characters, player name is 12 characters.
; Allocate 64 bytes to allow modders not to care too much and think
; about checking with strlen sometime.
sub esp, 64
push offset command
push esp
call strcpy
; eax and esp should be the same thing here.
push [ebp+8]
push eax
call strcat
push 5
push eax
call winexec
; Remove buffer
add esp, 64
; Wait for some indicator file to appear
; Subroutine epilogue
pop esi ; Restore caller's registers.
pop edi
pop ebx
mov esp, ebp ; Deallocate our local variables (if we used any)
; and restore esp.
pop ebp ; Restore ebp
ret
@Yitzi
What do you know about SMAX's runtime memory management? I need to allocate a decent size buffer (~64 bytes) for building a string for winexec.
The simplest approach that occurs to me is just to write to use the next 64 bytes of the stack as a buffer, but if SMAX uses the stack inappropriately that will cause problems.
Where in memory do you put your new variables?
Also, where in the file do you put your new constants and functions? There's a lot of empty space around, but I don't know if SMAC writes to it or not.
Code: [Select]play_video:
; Subroutine prologue
push ebp ; Store the caller's base pointer for later.
mov ebp, esp ; Replace base pointer with stack pointer for easier
; calls.
push ebx ; Store caller's registers we might use
push edi
push esi
; Subroutine body
; Accept one parameter, concatenate it with a constant string and pass
; to WinExec.
; Need a large buffer for string concatenation.
It's got some boilerplate function stuff in it at the moment that I might later purge to recover space. It also allows a buffer overflow attack from movlist.txt and doesn't yet wait for the external binary to finish.
However, I have found a buffer at 9B86A0, and it seems to be fairly large (more than 64 bytes); you'll have to make sure it's not currently in use, but that seems your best bet.
QuoteNeed a large buffer for string concatenation.Yeah, that's what 9B86A0 is usually used for.
If you want me to add it, you'd also have to replace the external calls with something that I can actually put it. (Well, the call to winexec, at least. I know where strcat is, and that can be used to imitate strcpy just by setting the first byte to 0 and then calling strcpy.)
Re: unused writable memory,
Thanks for the suggestion, I may use that for a "which film interface" type switch.
Re: unused executable memory,
I'll just dump everything at the end of the executable section for now, then.
That's contradictory. Have you ever seen SMAC use any of the writable memory around 9B86A0?
Thanks for the offer. The code isn't ready yet (not feature complete, not tested), but when it is I'll be sure to send you what you need with addresses based off your latest patch.
strcat and strcpy are standard C functions that have been rendered in the main body of the code. The call to WinExec goes into Kernel32.dll. I find them all with IDA Pro, but I can give you exact addresses to use once the code is ready to include.
mov ecx, [esp+arg_0]
push edi
test ecx, 3
jz short loc_644C7C
push edi
mov edi, [esp+arg_0]
jmp short loc_644CC1
I'm looking in IDA at (I believe) scient modded terranx.exe. I have strcat at 644C60 and strcpy at 644C50
strcat starts:Code: [Select]mov ecx, [esp+arg_0]
push edi
test ecx, 3
jz short loc_644C7C
strcpy starts:Code: [Select]push edi
mov edi, [esp+arg_0]
jmp short loc_644CC1
I have 645470 as possibly in the middle of a function. 645460 looks to be the start of that function, but I don't know what it does.
IDA finds strcat at 645470 in 2.5j, as you say. strcpy is at 645460. The content is the same as in the gog version, just a different offset.
strlen is at 6453e0.
There are a bunch of other potentially useful C functions baked in, too. You might want to consider getting the freeware version of IDA Pro and perusing the Functions and Imports windows; it's quite good at working out what functions are.
If you're running out of runtime memory, for instance, you could use the malloc function and move all your stuff into there. Should be safer, too, if you can't guarantee that various parts of the standard memory aren't writable. (I think malloc gets more memory off the heap, which should mean it doesn't interfere with the existing memory).