Jump to content


Photo

Modifying Outgoing Packet

packetmodified

    4 replies to this topic

    #1 Nifim

    Nifim

      Member

    • Members
    • PipPip
    • 13 posts
    • LocationWashington

    Posted 06 November 2016 - 04:45 PM

    Hi, 

    I have been trying to write a hp(home point) addon that would let me type "//hp {West Adoulin} A" while in a hp menu and then send the packet to teleport to that hp.

     

    i decided the safest way to start was modify the outgoing packet when you press esc here is an example of the code:

    windower.register_event('outgoing chunk',function(id,data, modified, injected, blocked)
        if id == 0x05b then
          local p = packets.parse('outgoing', data)
          if p["Option Index"] == 0 and p["_unknown1"] == 16384 then      
                p["Option Index"] = 2
                p["_unknown1"] = 38
                p["Automated Message"] = true     
            modified = p._raw
          end
        end
      end)
    

    This example sets the hp to Port Jeuno Moghouse(home point #2). I believe I am miss understanding how modifying a packet on its way out is supposed to work

     

    :x i am also pretty sure even if modified was goin out the p._raw is actually just the packet i stated with  and was not changed by me changing some of the fields.

     

    so to sum it all up how does one modify a packet? many examples i tracked down dont use the packets lib and i really want to use the lib cause it feels safer



    #2 trv

    trv

      Advanced Member

    • Members
    • PipPipPip
    • 34 posts

      Posted 06 November 2016 - 11:25 PM

      The packets library will be a little easier to understand if you clear up a few other details about the packet events.

      The game client and server communicate at discrete intervals. Since the flow of information isn't continuous, they
      each cram as much information as possible into each communication. What they actually send back and forth are giant
      strings of binary data (packets), which they then break up into the smaller "chunks" of information (hp updates,
      information about mobs, etc.). Confusingly, everyone has taken to calling the chunks (hence 'incoming chunk'/
      'outgoing chunk') packets, but the important bit is that packets (or more properly, chunks) are just strings.

      When you call windower.register_event, you pass it a string and a function. The string tells Luacore during which event to
      call the function. When the event occurs, Luacore calls the function and passes it the arguments listed on the dev wiki
      and, depending on the event, might use any return value to alter what occurs in the game-client process after the event.

      More specific to your code:

      windower.register_event('outgoing chunk',function(id,data, modified, injected, blocked)
      ...
      end)


      You've told Luacore to call an anonymous function when the client attempts to add a chunk to the next not-yet-fully-
      formed outgoing packet. You've defined five parameters in the function, and Luacore will pass the following
      arguments to each:
          id -- Luacore will pass a number to this parameter which identifies the type of information in the chunk.
                Luacore pulls this out of the first four bytes of data in the chunk (I think? I don't really remember),
                and someone has gone to great lengths to detail what type of information the number corresponds to in
                the fields.lua file.
          data -- Luacore will pass the chunk to this parameter. Some people label this parameter 'original' to distinguish
                  it from the next parameter.
          modified -- The incoming/outgoing chunk events both use return values from your functions to modify the string that
                      will eventually be tacked onto the forming packet. It's important to remember that your anonymous function
                      probably isn't the only function that Luacore is calling when the event occurs: other addons might ask
                      Luacore to handle the event as well. Luacore calls the functions in the order that it receives them, so if
                      another addon with an incoming/outgoing event was loaded first, that addon's function will run first and
                      may modify the chunk. Luacore will pass that modified version of the chunk to this parameter. If no other
                      addons have modified the chunk, this version will be the same as the argument sent to the previous parameter.
          injected -- Luacore will pass a boolean to this parameter which indicates if the chunk was created and injected by an
                      addon rather than by the client.
          blocked -- Luacore will pass a boolean to this parameter which indicates if another addon has requested that the chunk
                     not be added to the packet. Your addon can request this by registering a function which returns the boolean
                     value true. If the chunk is not added to the packet, the server will not receive any of the information
                     contained in the chunk.

      What's important to keep in mind here is that the function you pass to windower.register_event is just a function.
      It operates like any other function you'd write, and the only thing you really have to be sure to do is to declare a parameter
      for each argument you expect Luacore to pass for the event.

          if id == 0x05b then
              ...
          end

      You've identified which type of chunk should be analyzed. Primo!

            local p = packets.parse('outgoing', data)

      You've called the packets library function 'parse' and passed the direction of the chunk and the original, unmodified chunk.
      The parse function takes the chunk-a string, which is not very human-readable, and uses the bit and pack libraries along with the
      description of the chunk in fields.lua to form a table with keys and values that are readable representations of the data
      contained in the chunk.

            if p["Option Index"] == 0 and p["_unknown1"] == 16384 then      
                  p["Option Index"] = 2
                  p["_unknown1"] = 38
                  p["Automated Message"] = true     
              modified = p._raw
            end

      You've changed the values of a few keys in the table created by the parse function. That's fine, and if you want to modify the chunk,
      that's the first step. (Side note: if you know what the _unknown1 field's data is, you should update fields.lua with a description and
      a name that indicates its use, and submit a pull request on Github.) Next, you've done something strange: you've set modified, a parameter
      of your function which Luacore passed the modified version of the chunk to, equal to p._raw, which is a copy of the original chunk passed
      to the parse function. There's nothing syntactically incorrect about reassigning the value of a parameter, but parameters are essentially
      local variables; Luacore can't see them, or anything else that happens inside of the function. It just throws some arguments at a function
      you defined and hopes for the best.
      In order to communicate back to Luacore via the outgoing chunk event, you need to return a value from the function. Earlier, I said that
      returning true would tell Luacore not to add the chunk to the packet. Returning a string instead will tell Luacore that you want it to
      add that string to the packet instead of the original chunk.
      There remains one hurdle: you don't have a string to return. The parse function left you with a table. It contains all of the information
      needed to form the string, but it's not concatenated and it's not in the correct order. Luckily the build function in the packets library
      handles recreating the string, so you're closer than you think.
          return packets.build(p)

      That should do it.

      Things you might consider:
      You're modifying the original chunk, rather than the modified version. If an addon had previously modified the chunk, you've scrapped
      its changes. That's probably not a problem in this case, but in general it could cause a problem.

      Other stuff:
      The packets library is generally "safer" in that it's easier to use. It's also more readable! It's nice for anyone who's reading over your
      addon, because they don't have to pull out their copy of fields.lua and lookup the packing strings just to figure out what you're doing.
      The only downside is that it does parse the entire chunk by default, which might seem wasteful if you're only after one value. Generally,
      that's no big deal (computers are fast) and you can tell it not to parse values by passing a table to packets.parse as well. The only time
      you shouldn't use it is when you want to analyze the action packet, which is big and weird. You can use the actions library for that.

      #3 Nifim

      Nifim

        Member

      • Members
      • PipPip
      • 13 posts
      • LocationWashington

      Posted 07 November 2016 - 01:59 AM

      :D thank you for the answer clears up a lot for me! looks like i still have more research to do simply swapping the esc menu packet out for a warp request doesn't warp me. seems i need to also force the second packet that follows the first request. but using it to redirect a warp request worked :D so thanks a bunch for answering 

       

      edit: cool got it to work using the esc key here is the code block --

      windower.register_event('outgoing chunk',function(id,data, modified, injected, blocked)
          if id == 0x05b then
            local p = packets.parse('outgoing', data)
            --windower.add_to_chat(4, p._raw)
            if p["Option Index"] == 0 and p["_unknown1"] == 16384 then      
              p["Option Index"] = 2
              p["_unknown1"] = 38
              p["Automated Message"] = true  
              p2 = p
              p2["Automated Message"] = false
              packets.inject(p2)
              return packets.build(p)
            end
          end
        end)
      

      I do notice 1 thing when doing this, they hp warp happen faster then normal i dont see any animation or fade to black like a normal warp is that a bad or "detectable" thing SE will notice? i think it is because there is little to no delay between the first and second packets.



      #4 trv

      trv

        Advanced Member

      • Members
      • PipPipPip
      • 34 posts

        Posted 07 November 2016 - 03:39 AM

        I don't know if it would be detected. As written, there is no delay between the chunks. They'll be consecutive within the packet so long as there's room. I also don't know if that's normal (I've never looked at 0x05B).

         

        Looking at the edited version, it looks like you've made an error:

         

        p2 = p
        p2["Automated Message"] = false
        packets.inject(p2)
        return packets.build(p)
        

        Firstly, p2 is defined globally, which might be unintentional. Secondly, tables are passed by reference in Lua, so when you write p2 = p you're not creating a new table, you're pointing the variable p2 to the same table that the local variable p is looking at. This means that when you next write p2["Automated Message"]=false, you're also setting p["Automated Message"] = false. I don't think that was your intent.

        As written, it will add two identical 0x05B chunks to the outgoing packet. It seems like it works, so it's up to you if you want to make changes to better replicate the client generated packets.

         

        As a side note, you've called packets.inject passing it the table built by packets.parse. That's the correct thing to do in this case -- you haven't made any errors there, I only want to point out that if you were trying to build a packet from scratch you would need to use packets.new. Aaaaaaaand that's pretty much the whole packets library! It's deceptively small given what it's capable of.



        #5 Sammeh

        Sammeh

          Member

        • Members
        • PipPip
        • 24 posts

          Posted 11 December 2016 - 11:22 AM

          Hey first post - interestingly enough ffxiah deleted my other one.  I had written this exact same LUA (or goal anyway) and didn't realize it here.

           

          Can download here:

          https://1drv.ms/u/s!...dPuxWMvHV_-svkQ






          1 user(s) are reading this topic

          0 members, 1 guests, 0 anonymous users