Search code examples
assemblyscriptingx86cheat-engine

Where is the difference between those two Assembly code snippet's?


  push eax
  push str_checkSell
  call CELUA_ExecuteFunction //we assume this returns 1
  test eax, eax
  jz AutoMarketInc // This doesnt effect the programm cause eax = 1
  push eax // Why do we push eax again?
  push str_getSellQuantity
  call CELUA_ExecuteFunction // we assume this returns 1
  push eax // why to we push eax two times?
  push eax //
  push str_getGood
  call CELUA_ExecuteFunction // This returns 2
  push eax //this eax now 2?
  push 1 //just a one on the stack I assume?
  call 004CBFA0 // Function call with arguments? (Func takes 3 arguments)

So far so good, now I want to replace the Lua-Functions with static values

  push eax
  mov eax,1
  test eax, eax
  jz AutoMarketInc // This doesnt effect the programm cause eax = 1
  push eax // Why do we push eax again?
  mov eax,1
  push eax // why to we push eax two times?
  push eax //
  mov eax,2
  push eax //this eax now 2?
  push 1 //just a one on the stack I assume?
  call 004CBFA0 // Function call with arguments? (Func takes 3 arguments)

Am I understand this whole thing correctly? Are my comments correct?

When I repalce the first code with the second one my target process crashes which I try to manipulate.

In case you need further informations:

Its about a game where you can micro manage goods, the function call 004CBFA0 sells items

The code is not mine its an Script which handles the auto sell and works well. But I just replaced the lines as you can see above and its not working anymore? Shouldnt it work cause I just use static values instead of dynamic ones?

LUA Script:

----------------
-- Goods List --
----------------

GOODS_ID = {}
GOODS_ID.wood     = 2
GOODS_ID.hop      = 3
GOODS_ID.stone    = 4
GOODS_ID.iron     = 6
GOODS_ID.pitch    = 7
GOODS_ID.wheat    = 9
GOODS_ID.bread    = 10
GOODS_ID.cheese   = 11
GOODS_ID.meat     = 12
GOODS_ID.fruit    = 13
GOODS_ID.beer     = 14
GOODS_ID.flour    = 16
GOODS_ID.bow      = 17
GOODS_ID.xbow     = 18
GOODS_ID.spear    = 19
GOODS_ID.pike     = 20
GOODS_ID.mace     = 21
GOODS_ID.sword    = 22
GOODS_ID.leather  = 23
GOODS_ID.armor    = 24



-----------------
-- Lua Scripts --
-----------------

good_id = 1
-- current good, or more precise, index of MARKET_LIST

function getGood()
  -- returns current good id
  return GOODS_ID[MARKET_LIST[good_id][1]]
end

function getGoodCount(good)
  -- returns current number of good in stockple/granary/armory
  local GOODS_BASE = 0x0115FCBC -- 1.4.1
  return readInteger(GOODS_BASE + 4 * GOODS_ID[good])
end

function checkBuy()
  -- returns 1 if current something of the current good should be bought, else 0
  local good_arr = MARKET_LIST[good_id]
  if getGoodCount(good_arr[1]) < good_arr[2] - good_arr[4] then
    return 1
  end
  return 0
end

function getBuyQuantity()
  -- returns how much of the current good should be bought
  local good_arr = MARKET_LIST[good_id]
  local count = getGoodCount(good_arr[1])
  return good_arr[2] - count
end

function checkSell()
  -- returns 1 if current something of the current good should be sold, else 0
  local good_arr = MARKET_LIST[good_id]
  if getGoodCount(good_arr[1]) > good_arr[3] + good_arr[5] then
    return 1
  end
  return 0
end

function getSellQuantity()
  -- returns how much of the current good should be sold
  local good_arr = MARKET_LIST[good_id]
  local count = getGoodCount(good_arr[1])
  return count - good_arr[3]
end

function nextGood()
  -- increments good_id for next iteration
  if good_id < #MARKET_LIST then
    good_id = good_id + 1
  else
    good_id = 1
  end
end
{$lua}
------------------
-- Market Setup --
------------------

--[[
You can add any good you want to trade to the automatic market by adding
{"good", min, max, min_variance, max_variance}
to the MARKET_LIST. All goods below the MARKET_LIST.
Check, that min-min_variance > 0.
The market only buys or sells one good per gametick!
--]]

MARKET_LIST = {
{"wood",   10, 25, 5, 10},
{"bread",  15, 50, 5, 20},
{"cheese", 15, 50, 5, 20},
{"meat",   15, 50, 5, 20},
{"fruit",  15, 50, 5, 20}}

--[[
wood
hop
stone
iron
pitch
wheat
bread
cheese
meat
fruit
beer
flour
bow
xbow
spear
pike
mace
sword
leather
armor
--]]



---------------------
-- Assembly Script --
--- Don't touch ! ---
---------------------

{$asm}
loadlibrary(luaclient-i386.dll)
luacall(openLuaServer('CELUASERVER'))

CELUA_ServerName:
db 'CELUASERVER',0

alloc(functionid,32)
alloc(str_getGood,64)
alloc(str_checkBuy,64)
alloc(str_getBuyQuantity,64)
alloc(str_checkSell,64)
alloc(str_getSellQuantity,64)
alloc(str_nextGood,64)

str_getGood:
db 'return getGood(parameter)',0
str_checkBuy:
db 'return checkBuy(parameter)',0
str_getBuyQuantity:
db 'return getBuyQuantity(parameter)',0
str_checkSell:
db 'return checkSell(parameter)',0
str_getSellQuantity:
db 'return getSellQuantity(parameter)',0
str_nextGood:
db 'return nextGood(parameter)',0



[ENABLE]

aobscanmodule(AutoMarketInject,Stronghold Crusader.exe,E9 9F E7 FF FF)
alloc(AutoMarketMem,$1000)
label(AutoMarketInit)
label(AutoMarketBuy)
label(AutoMarketSell)
label(AutoMarketInc)
label(AutoMarketReturn)

registersymbol(AutoMarketInject)
registersymbol(AutoMarketMem)
registersymbol(AutoMarketInit)
registersymbol(AutoMarketBuy)
registersymbol(AutoMarketSell)
registersymbol(AutoMarketInc)
registersymbol(AutoMarketReturn)


AutoMarketInject:
  jmp AutoMarketMem

AutoMarketMem:

AutoMarketInit:
  push ecx
// checks if appropriate gametick
  cmp dword ptr [117CACC],00
  jz AutoMarketReturn

AutoMarketBuy:
// checks and might buy
  push eax
  push str_checkBuy
  call CELUA_ExecuteFunction
  test eax,eax
  jz AutoMarketSell
  push eax
  push str_getBuyQuantity
  call CELUA_ExecuteFunction
  push eax
  push eax
  push str_getGood
  call CELUA_ExecuteFunction
  push eax
  push 1
  call 004CC000
  jmp AutoMarketInc

AutoMarketSell:
// checks and might sell
  push eax
  push str_checkSell
  call CELUA_ExecuteFunction
  test eax, eax
  jz AutoMarketInc
  push eax
  push str_getSellQuantity
  call CELUA_ExecuteFunction
  push eax
  push eax
  push str_getGood
  call CELUA_ExecuteFunction
  push eax
  push 1
  call 004CBFA0

AutoMarketInc:
// increments current good
  push eax
  push str_nextGood
  call CELUA_ExecuteFunction

AutoMarketReturn:
// return
  pop ecx
  jmp 0045B4A0



[DISABLE]

AutoMarketInject:
  db E9 9F E7 FF FF


dealloc(AutoMarketMem)

dealloc(str_getGood,64)
dealloc(str_checkBuy,64)
dealloc(str_getBuyQuantity,64)
dealloc(str_checkSell,64)
dealloc(str_getSellQuantity,64)
dealloc(str_nextGood,64)

unregistersymbol(AutoMarketInject)
unregistersymbol(AutoMarketMem)
unregistersymbol(AutoMarketInit)
unregistersymbol(AutoMarketBuy)
unregistersymbol(AutoMarketSell)
unregistersymbol(AutoMarketInc)
unregistersymbol(AutoMarketReturn)

Source: https://github.com/UnofficialCrusaderPatch/UnofficialCrusaderPatch/issues/512


Solution

  • I'm making the assumption that the calling convention for the function CELUA_ExecuteFunction is that the called function removes its parameters from the stack when it returns. I'm pretty sure that is correct, because the code doesn't make sense otherwise.

    All of the pushes in this code are placing parameters on the stack in preparation for a function call. For each function call you remove, you must also remove the code that pushes its parameters, so that the stack remains balanced.

    The first two pushes are parameters to the first function call, which you removed, so you should also remove both of the pushes, not just the second one.

    The next two pushes are parameters to the second function call. Again, you need to remove both.

    The next push is the third parameter to the function 004CBFA. You need to keep this one. (The value is the return value of getSellQuantity.)

    The next two pushes are parameters to the third function call. Again, you need to remove both. Note that the second parameter to getGood is the same as the third parameter to 004CBFA. That's why eax is pushed twice.

    After removing the parameters to the function calls that you removed, you are left with only 3 pushes: push 1, push 2, and push 1.