def f_dwepdread_epd_safe(targetplayer): ret, retepd = c.EUDVariable(), c.EUDVariable() # Common comparison rawtrigger c.PushTriggerScope() cmpc = c.Forward() cmp_player = cmpc + 4 cmp_number = cmpc + 8 cmpact = c.Forward() cmptrigger = c.Forward() cmptrigger << c.RawTrigger( conditions=[cmpc << c.Memory(0, c.AtMost, 0)], actions=[cmpact << c.SetMemory(cmptrigger + 4, c.SetTo, 0)]) cmpact_ontrueaddr = cmpact + 20 c.PopTriggerScope() # static_for chain1 = [c.Forward() for _ in range(32)] chain2 = [c.Forward() for _ in range(32)] # Main logic start c.SeqCompute([(ut.EPD(cmp_player), c.SetTo, targetplayer), (ut.EPD(cmp_number), c.SetTo, 0xFFFFFFFF), (ret, c.SetTo, 0xFFFFFFFF), (retepd, c.SetTo, ut.EPD(0) + 0x3FFFFFFF)]) readend = c.Forward() for i in range(31, -1, -1): nextchain = chain1[i - 1] if i > 0 else readend if i >= 2: epdsubact = [retepd.AddNumber(-2**(i - 2))] epdaddact = [retepd.AddNumber(2**(i - 2))] else: epdsubact = [] epdaddact = [] chain1[i] << c.RawTrigger( nextptr=cmptrigger, actions=[ c.SetMemory(cmp_number, c.Subtract, 2**i), c.SetNextPtr(cmptrigger, chain2[i]), c.SetMemory(cmpact_ontrueaddr, c.SetTo, nextchain), ret.SubtractNumber(2**i), ] + epdsubact) chain2[i] << c.RawTrigger(actions=[ c.SetMemory(cmp_number, c.Add, 2**i), ret.AddNumber(2**i), ] + epdaddact) readend << c.NextTrigger() return ret, retepd
def EUDJump(nextptr): if isinstance(nextptr, c.EUDVariable): t = c.Forward() c.SeqCompute([(ut.EPD(t + 4), c.SetTo, nextptr)]) t << c.RawTrigger() else: c.RawTrigger(nextptr=nextptr)
def _f_mul(a, b): ret, y0 = ev.EUDCreateVariables(2) # Init ev.SeqCompute([(ret, rt.SetTo, 0), (y0, rt.SetTo, b)]) chain = [ac.Forward() for _ in range(32)] chain_y0 = [ac.Forward() for _ in range(32)] # Calculate chain_y0 for i in range(32): ev.SeqCompute(((ut.EPD(chain_y0[i]), rt.SetTo, y0), (y0, rt.Add, y0))) if i <= 30: p1, p2, p3 = ac.Forward(), ac.Forward(), ac.Forward() p1 << rt.RawTrigger(nextptr=p2, conditions=a.AtMost(2**(i + 1) - 1), actions=rt.SetNextPtr(p1, p3)) p3 << rt.RawTrigger(nextptr=chain[i], actions=rt.SetNextPtr(p1, p2)) p2 << rt.NextTrigger() # Run multiplication chain for i in range(31, -1, -1): cy0 = ac.Forward() chain[i] << rt.RawTrigger( conditions=[a.AtLeast(2**i)], actions=[a.SubtractNumber(2**i), cy0 << ret.AddNumber(0)]) chain_y0[i] << cy0 + 20 return ret
def _f_div(a, b): ret, x = ev.EUDCreateVariables(2) # Init ev.SeqCompute([ (ret, rt.SetTo, 0), (x, rt.SetTo, b), ]) # Chain ac.Forward decl chain_x0 = [ac.Forward() for _ in range(32)] chain_x1 = [ac.Forward() for _ in range(32)] chain = [ac.Forward() for _ in range(32)] # Fill in chain for i in range(32): ev.SeqCompute([ (ut.EPD(chain_x0[i]), rt.SetTo, x), (ut.EPD(chain_x1[i]), rt.SetTo, x), ]) # Skip if over 0x80000000 p1, p2, p3 = ac.Forward(), ac.Forward(), ac.Forward() p1 << rt.RawTrigger(nextptr=p2, conditions=x.AtLeast(0x80000000), actions=rt.SetNextPtr(p1, p3)) p3 << rt.RawTrigger(nextptr=chain[i], actions=rt.SetNextPtr(p1, p2)) p2 << rt.NextTrigger() ev.SeqCompute([ (x, rt.Add, x), ]) # Run division chain for i in range(31, -1, -1): cx0, cx1 = ac.Forward(), ac.Forward() chain[i] << rt.RawTrigger( conditions=[cx0 << a.AtLeast(0)], actions=[cx1 << a.SubtractNumber(0), ret.AddNumber(2**i)]) chain_x0[i] << cx0 + 8 chain_x1[i] << cx1 + 20 return ret, a # a : remainder
def CreatePayloadRelocator(payload): # We first build code injector. prtdb = c.Db(b''.join([ut.i2b4(x // 4) for x in payload.prttable])) prtn = c.EUDVariable() ortdb = c.Db(b''.join([ut.i2b4(x // 4) for x in payload.orttable])) ortn = c.EUDVariable() orig_payload = c.Db(payload.data) if c.PushTriggerScope(): root = c.NextTrigger() # Verify payload # Note : this is very, very basic protection method. Intended attackers # should be able to penetrate through this very easily # init prt prtn << len(payload.prttable) if payload.prttable: if cs.EUDWhile()(prtn >= 1): cs.DoActions(prtn.SubtractNumber(1)) sf.f_dwadd_epd( ut.EPD(orig_payload) + sf.f_dwread_epd(prtn + ut.EPD(prtdb)), orig_payload // 4) cs.EUDEndWhile() # init ort ortn << len(payload.orttable) if payload.orttable: if cs.EUDWhile()(ortn >= 1): cs.DoActions(ortn.SubtractNumber(1)) sf.f_dwadd_epd( ut.EPD(orig_payload) + sf.f_dwread_epd(ortn + ut.EPD(ortdb)), orig_payload) cs.EUDEndWhile() # Jump cs.EUDJump(orig_payload) c.PopTriggerScope() return c.CreatePayload(root)
def f_dwepdCUnitread_epd(targetplayer): origcp = f_getcurpl() ptr, epd = c.EUDVariable(), c.EUDVariable() cs.DoActions([ ptr.SetNumber(0x59CCA8), epd.SetNumber(ut.EPD(0x59CCA8)), c.SetCurrentPlayer(targetplayer) ]) for i in range(10, -1, -1): c.RawTrigger(conditions=[ c.Deaths(c.CurrentPlayer, c.AtLeast, 0x59CCA8 + 336 * 2**i, 0) ], actions=[ c.SetDeaths(c.CurrentPlayer, c.Subtract, 336 * 2**i, 0), ptr.AddNumber(336 * 2**i), epd.AddNumber(84 * 2**i) ]) cs.DoActions(c.SetDeaths(c.CurrentPlayer, c.SetTo, ptr, 0)) f_setcurpl(origcp) return ptr, epd
def CreateVectorRelocator(chkt, payload): global trglist # Append 'Require EUD enabler' to string table str_section = chkt.getsection('STR') strtb = c.TBL(str_section) eude_needed = strtb.GetStringIndex('This map requires EUD Enabler to run') str_section = strtb.SaveTBL() ''' Algorithm credit to [email protected] Overall algorithm : STR <-> MRGN cycle MRGN: SetMemory(payload, Add, payload_offset // 4) MRGN <-> STR0 = Trigger(actions=[ STR1 [SetMemory( mrgn.action[i].player, Add, prttable[j+packn] - prttable[j] ) for i in range(packn)], STR2 SetNextPtr(mrgn, STR[k+1]) ... ) ''' mrgn = 0x58DC60 packn = 15 ############# # STR SECTION ############# str_sled = [] sledheader_prt = b'\0\0\0\0' + ut.i2b4(mrgn) sledheader_ort = b'\0\0\0\0' + ut.i2b4(mrgn + 2408) # apply prt prttrg_start = 2408 * len(str_sled) # = 0 # mrgn.action[i].player = EPD(payload_offset) + prevoffset[i] prevoffset = [-1] * packn for i in range(0, len(payload.prttable), packn): prts = list(map(lambda x: x // 4, payload.prttable[i: i + packn])) prts = prts + [-1] * (packn - len(prts)) # -1 : dummy space pch = [prts[j] - prevoffset[j] for j in range(packn)] str_sled.append(sledheader_prt + tt.Trigger( players=[tt.AllPlayers], actions=[ [tt.SetMemory(mrgn + 328 + 32 * j + 16, tt.Add, pch[j]) for j in range(packn)], ] )) prevoffset = prts # apply ort orttrg_start = 2408 * len(str_sled) # = 0 # mrgn.action[i].player = EPD(payload_offset) + prevoffset[i] prevoffset = [-1] * packn for i in range(0, len(payload.orttable), packn): orts = list(map(lambda x: x // 4, payload.orttable[i: i + packn])) orts = orts + [-1] * (packn - len(orts)) # -1 : dummy space pch = [orts[j] - prevoffset[j] for j in range(packn)] str_sled.append(sledheader_ort + tt.Trigger( players=[tt.AllPlayers], actions=[ [tt.SetMemory(mrgn + 2408 + 328 + 32 * j + 16, tt.Add, pch[j]) for j in range(packn)], ] )) prevoffset = orts # jump to ort str_sled.append(sledheader_ort + tt.Trigger( players=[tt.AllPlayers], actions=[ [tt.SetMemory(mrgn + 2408 + 328 + 32 * j + 16, tt.Add, 0xFFFFFFFF - prevoffset[j]) for j in range(packn)], tt.SetMemory(mrgn + 2408 + 4, tt.Add, 4) # skip garbage area ] )) # sled completed str_sled = b''.join(str_sled) str_padding_length = -len(str_section) & 3 strsled_offset = len(str_section) + str_padding_length payload_offset = strsled_offset + len(str_sled) + 4 str_section = str_section + \ bytes(str_padding_length) + str_sled + b'\0\0\0\0' + payload.data chkt.setsection('STR', str_section) ############## # MRGN SECTION ############## mrgn_trigger = [] mrgn_trigger.append( bytes(4) + ut.i2b4(prttrg_start + strsled_offset) + tt.Trigger( players=[tt.AllPlayers], actions=[ # SetDeaths actions in MRGN initially points to EPD(payload - # 4) [tt.SetMemory(payload_offset - 4, tt.Add, payload_offset // 4) for _ in range(packn)], tt.SetMemory(mrgn + 4, tt.Add, 2408) ] ) ) mrgn_trigger.append( bytes(4) + ut.i2b4(orttrg_start + strsled_offset) + tt.Trigger( players=[tt.AllPlayers], actions=[ [tt.SetMemory(payload_offset - 4, tt.Add, payload_offset) for _ in range(packn)], tt.SetMemory(mrgn + 2408 + 4, tt.Add, 2408) ] ) ) mrgn_section = b''.join(mrgn_trigger) + bytes(5100 - 2408 * 2) chkt.setsection('MRGN', mrgn_section) ############## # TRIG SECTION ############## trglist.clear() # Check if epd is supported Trigger( actions=[ tt.SetDeaths(-12, tt.SetTo, 1, 1) ]) Trigger( conditions=[ tt.Deaths(0, tt.Exactly, 0, 0) ], actions=[ tt.DisplayText(eude_needed), tt.Draw() ] ) # End trigger execution if EUDA is not supported # - using condition #115 twice. Trigger( conditions=[ tt.Deaths(0, tt.Exactly, 0, 0), tt.Condition(0, 0, 0, 0, 0, 115, 0, 0), tt.Condition(0, 0, 0, 0, 0, 115, 0, 0), ] ) Trigger(actions=[ tt.SetDeaths(-12, tt.SetTo, 0, 1) ]) # ------- # Init mrgn rawtrigger strs = 0x5993D4 for e in range(31, 1, -1): # prt table # player Trigger( conditions=tt.Memory(strs, tt.AtLeast, 2 ** e), actions=[ [tt.SetMemory(mrgn + 328 + 32 * i + 16, tt.Add, 2 ** (e - 2)) for i in range(packn)], tt.SetDeaths(11, tt.Add, 2 ** e, 0), [tt.SetMemory(mrgn + 328 + 32 * i + 20, tt.Add, 2 ** (e - 2)) for i in range(packn)], tt.SetMemory(mrgn + 4, tt.Add, 2 ** e), [tt.SetMemory( mrgn + 2408 + 328 + 32 * i + 16, tt.Add, 2 ** (e - 2)) for i in range(packn)], tt.SetMemory(mrgn + 2408 + 4, tt.Add, 2 ** e), [tt.SetMemory(mrgn + 2408 + 328 + 32 * i + 20, tt.Add, 2 ** e) for i in range(packn)], tt.SetMemory(strs, tt.Subtract, 2 ** e), ] ) for e in range(31, 1, -1): Trigger( conditions=tt.Deaths(11, tt.AtLeast, 2 ** e, 0), actions=[ tt.SetDeaths(11, tt.Subtract, 2 ** e, 0), tt.SetMemory(strs, tt.Add, 2 ** e) ] ) # Payload update curpl = 0x6509B0 # ------- # pts[player].lasttrigger->next = value(strs) + strsled_offset pts = 0x51A280 for player in range(8): triggerend = ~(0x51A284 + player * 12) Trigger( players=[player], actions=[ tt.SetMemory(curpl, tt.SetTo, ut.EPD(pts + 12 * player + 4)), tt.SetDeaths(9, tt.SetTo, triggerend, 0) # Used in stage 2 ] ) # read pts[player].lasttrigger for e in range(31, 1, -1): Trigger( conditions=tt.Deaths(tt.CurrentPlayer, tt.AtLeast, 2 ** e, 0), actions=[ tt.SetDeaths(tt.CurrentPlayer, tt.Subtract, 2 ** e, 0), tt.SetDeaths(10, tt.Add, 2 ** e, 0), tt.SetDeaths(11, tt.Add, 2 ** e, 0), ] ) for e in range(31, 1, -1): Trigger( conditions=tt.Deaths(10, tt.AtLeast, 2 ** e, 0), actions=[ tt.SetDeaths(10, tt.Subtract, 2 ** e, 0), tt.SetDeaths(tt.CurrentPlayer, tt.Add, 2 ** e, 0) ] ) # apply to curpl Trigger(actions=[ tt.SetDeaths(10, tt.SetTo, ut.EPD(4), 0), tt.SetMemory(curpl, tt.SetTo, ut.EPD(4)) ]) for e in range(31, 1, -1): Trigger( conditions=tt.Deaths(11, tt.AtLeast, 2 ** e, 0), actions=[ tt.SetDeaths(11, tt.Subtract, 2 ** e, 0), # used for nextptr recovery in stage 3 tt.SetDeaths(10, tt.Add, 2 ** (e - 2), 0), tt.SetMemory(curpl, tt.Add, 2 ** (e - 2)) ] ) # now curpl = EPD(value(ptsprev) + 4) # value(EPD(value(ptsprev) + 4)) = strs + payload_offset CopyDeaths(tt.EPD(strs), tt.CurrentPlayer, False, strsled_offset) # Done! trigdata = b''.join(trglist) # Stage 1 created # ------- # Previous rawtrigger datas oldtrigraw = chkt.getsection('TRIG') oldtrigs = [oldtrigraw[i:i + 2400] for i in range(0, len(oldtrigraw), 2400)] proc_trigs = [] # Collect only enabled triggers for trig in oldtrigs: trig = bytearray(trig) flag = ut.b2i4(trig, 320 + 2048) if flag & 8: # Trigger already disabled pass flag ^= 8 # Disable it temporarilly. It will be re-enabled at stage 3 trig[320 + 2048: 320 + 2048 + 4] = ut.i2b4(flag) proc_trigs.append(bytes(trig)) oldtrigraw_processed = b''.join(proc_trigs) chkt.setsection('TRIG', trigdata + oldtrigraw_processed)