Advertisement
Guest User

ByteCode Conversion

a guest
Apr 17th, 2017
2,183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.94 KB | None | 0 0
  1. BYTECODE CONVERSION
  2. The idea behind RC7 and other, unheard (private) exploits
  3. Written by Louka
  4. PRESENTED BY
  5. RAIN
  6. Scripting and reversing group.
  7. Credits
  8. ❏ Brandon/Chirality: For inventing the first modern script execution exploit that
  9. preceded the most recent exploits, such as Intriga and Elysian. He’s also the
  10. reason why I got into exploits.
  11. ❏ Jordan/KingJordan: For inventing the concept of bytecode conversion and using it
  12. to create the exploit known as RC7, which is one of the most popular exploits.
  13. ❏ Rain: Rain is the spiritual successor to FaZe, and (personally speaking) one of
  14. the best reversing groups out here. Previous FaZe members still interested in
  15. Roblox exploiting found themselves in Rain shortly after its introduction to the
  16. Roblox exploit scene. I need to credit Rain for trying (and succeeding at that!)
  17. to improve the exploit section. They’re doing a good job.
  18. ❏ Louka: For creating and designing this document. That’s me! :P
  19. ❏ ConvexHero: For not doing anything. Well, he did implement callcheck, but that’s
  20. it. He’s doing relatively nothing that prevents exploits from happening.
  21. What is bytecode?
  22. Bytecode is basically the compiled form of source code. When you create a C++
  23. application in Visual Studio and build it, the compiler (MSVC) simply takes your source
  24. code then translates it into a set of simple instructions called assembly, which is
  25. then optimized (for speed and/or size) and put into an executable file. The executable
  26. code contains bytecode (along with resources, constant data and etc.)
  27. This does not only apply to C++ applications. In fact, almost every language in the
  28. world is compiled to another language easier to understand by your computer. Languages
  29. that are considered “interpreted” are usually compiled to a form of bytecode, which is
  30. then read by the interpreter to execute what the code does.
  31. Bytecode, unlike executable binaries, are very portable. Yeah, executable binaries ARE
  32. portable (it’s in their name: PE, portable executable), but bytecode is usually smaller
  33. and therefore more portable than entire files.
  34. Today, we’re going to talk about Lua bytecode.
  35. A short overview on Lua bytecode (pt. 1)
  36. So, we know that bytecode is mainly constituted of instructions. Let’s take a look at
  37. Lua instructions, shall we?
  38. ❖ Each instruction has four parameters: the opcode, the A register, the B register
  39. and the C register. Each are one byte long, which forms a single signed integer.
  40. An instruction that uses all three registers is of type iABC.
  41. ❖ Certain instructions merges the B register with the C register to form a short (an
  42. integer with two bytes), which can store bigger values. This creates the Bx (B
  43. extended) register. An instruction that uses the A and Bx registers is of type
  44. iABx. (instruction, A, Bx)
  45. ❖ Certain instructions have a signed Bx register (it can contain negative values).
  46. They are of the iAsBx type. (instruction, A, signed Bx)
  47. ❖ And there are instructions that simply uses the A register. They are of the iA
  48. type. (instruction, A). This is rare, though.
  49. A short overview on Lua bytecode (pt. 2)
  50. In the previous slide, I’ve mentioned opcodes. Opcodes is what tells the interpreter
  51. what the instruction does. If the instruction’s opcode is OP_ADD (iABC), then it tells
  52. the interpreter to put in the A register the sum of the values located at B and C.
  53. Lua has exactly 37 instructions, which is small if you compare Lua’s instruction set
  54. to, for example, x86’s instruction set (hint: on average, ~2000 instructions. CPUs are
  55. different so they all have different instruction sets, so the number of instructions is
  56. different depending on the CPU brand and the architecture.)
  57. Due to the opcode being stored as a single byte, there could be a maximum of 255
  58. instructions if Lua’s development team wanted to add more instructions. If they reach
  59. that number, then they would need to switch to 64bit integers (8 bytes). This also
  60. means they would be able to add in more registers, which could mean a more performant
  61. VM, but this is just a dream that’ll never happen.
  62. How could we use bytecode for script execution?
  63. First, let’s consider those facts:
  64. ❖ Lua bytecode is compiled Lua scripts.
  65. ❖ When you run a Lua script, Lua automatically compiles it to an intermediary format
  66. resembling bytecode before feeding it to the virtual machine.
  67. ❖ This “intermediary format” (which is a mere Proto struct) can be serialized then
  68. dumped as bytecode, which can be saved as a file.
  69. ❖ Then, if you wanted to run the bytecode, you just have to feed it to luaU_undump,
  70. which will convert the bytecode into Lua’s intermediary format (a Proto).
  71. ❖ Once you obtained the Proto, you can insert it into a Lua function (LClosure) then
  72. schedule it for execution.
  73. ❖ If a developer removes Lua’s compiler, then Lua could only run bytecode.
  74. Therefore, in theory, we could simply dump bytecode from an external Lua instance then
  75. feed it to another Lua instance so that other Lua instance can run a script for us
  76. without having to go through the compiler. This is in fact pretty useful, as Roblox
  77. removed the compiler, preventing us from compiling scripts on the client.
  78. So, how could we use it for Roblox script execution?
  79. In theory, you could basically do this:
  80. 1) Compile a Lua function on your own Lua environment.
  81. 2) Dump it into bytecode via either lua_dump or string.dump.
  82. 3) Save that bytecode somewhere, preferably in memory.
  83. 4) Call Roblox’s lua_loadbuffer to load in the bytecode, which will eventually invoke
  84. luaU_undump to convert it into a proto.
  85. 5) You insert the obtained Proto into a Lua function (LClosure)
  86. 6) You call the resulting function, effectively running your script.
  87. While the above would work in any other standard Lua environment, sadly, it doesn’t
  88. work in Roblox for a multitude of reasons, but the most important being the fact that
  89. Roblox has heavily modified their instruction set and added some obfuscation to it.
  90. This was done in order to prevent exploiters from simply copy and pasting Lua bytecode
  91. over to the client and expecting it to run. However, just like every security measure
  92. in the world, this does not prevent anybody from running bytecode, it just makes their
  93. task harder as they have to convert their bytecode, hence the name of the procedure:
  94. BYTECODE CONVERSION. You convert bytecode into Roblox’s format.
  95. Differences between Lua and Roblox Lua bytecode (pt. 1)
  96. ❖ Roblox Lua bytecode instructions are changed. That is, OP_MOVE in a normal Lua
  97. environment is 0, but in Roblox’s Lua environment, it’s 6. This is very easy to
  98. figure out and convert, whatsoever.
  99. ❖ Certain Roblox Lua instructions are obfuscated using a mixture of modular
  100. multiplicative inverses and a lot of bit math. To be honest, it’s a lot of boring
  101. stuff and it almost requires someone to possess a computer science degree to
  102. understand what Roblox is doing. Fortunately, we have smart people out here (cough
  103. Chirality, Alureon, Austin <3) who figured most of it out and were able to reverse
  104. Roblox’s obfuscation process. This obfuscation is only applied to OP_CALL,
  105. OP_TAILCALL, OP_RETURN and OP_CLOSURE. Every other encryption is not affected.
  106. ❖ Every instruction is obfuscated, albeit this form of obfuscation is easier to
  107. reverse than CALL/TAILCALL/RETURN/CLOSURE’s special encryption, as it’s virtually
  108. only multiplication. (deobfuscated opcode = obfusop * key). Of course, OBFUSCATING
  109. the opcode is the hard part here.
  110. ❖ OP_MOVE now uses the C register (normal Lua only used the A and B registers),
  111. turning it into an iABC instruction. The difference is only artificial and doesn’t
  112. have an actual usage in the virtual machine.
  113. Differences between Lua and Roblox Lua bytecode (pt. 2)
  114. ❖ The bytecode magic header (what is used by the undumper to verify if what you gave
  115. it is actually bytecode) has a different value. Of course, if you find this hard
  116. to reverse, you probably have to study reverse engineering a lil’ bit more :u
  117. ❖ The bytecode is compressed using LZ4, which is an extremely fast compression
  118. algorithm. This, again, isn’t difficult to reverse either, considering LZ4’s
  119. source code is available to everyone.
  120. ❖ The registers are reversed. That is, in normal Lua, the registers are ordered like
  121. this in the integer: A, B and C. In Roblox Lua, it’s C, B and A.
  122. This is all the differences we currently know of. There are some additional obfuscation
  123. and protection steps Roblox took but they’re only superficial and obvious so it’s not
  124. worth mentioning here. They would only take tens of minutes to reverse.
  125. I mean, that’s how much they took for me. Maybe some people will reverse it slower than
  126. I do. Who knows.
  127. How would someone convert Lua BC to Roblox BC?
  128. 1. The most important thing is converting instructions. You do it like this for every
  129. instruction in the bytecode dump:
  130. a. You take the opcode and find the corresponding Roblox opcode as they’ve
  131. changed. Then, you set the opcode in your instruction to that one.
  132. b. You set the C, B and A registers. Don’t forget that they’re reversed!
  133. c. If it’s OP_MOVE, then don’t forget to set the C register. They use it now as
  134. an artificial difference.
  135. d. If it’s an instruction with special encryption (OP_CALL, OP_TAILCALL,
  136. OP_RETURN and OP_CLOSURE), you apply the special encryption to the
  137. instruction.
  138. e. Finally, you apply general encryption to the instruction then put it into your
  139. output bytecode dump.
  140. 2. The second most important thing is moving stuff around. Of course, the bytecode
  141. dump’s structure must be changed in order for Roblox to accept it. In fact, Roblox
  142. has completely remade Lua’s bytecode format. They didn’t just modify it.
  143. 3. You also have to fix line number as well. Roblox now encrypts line numbers based
  144. on the line number’s associated instruction.
  145. Decompilation and such things
  146. Decompilers in modern exploits (Seven, Elysian, Intriga (if it has one) and etc) works
  147. by simply doing the reverse of bytecode conversion: converting Roblox bytecode into Lua
  148. bytecode. Then, the Lua bytecode is fed to a program (usually luadec) which creates
  149. pseudocode from the bytecode dump you obtained from your conversion.
  150. This process, however, is not without issues: my previous attempts at doing the reverse
  151. of bytecode conversion had a lot of issues (usually things with decryption and etc)
  152. which generated artifacts during the decompilation process. Relatively simple scripts,
  153. however, decompiled with a moderate amount of success.
  154. You could theoretically use proto conversion to achieve decompilation too: you convert
  155. a Roblox proto into a normal Lua proto, push it to a normal Lua state then call
  156. lua_dump or string.dump on it, which will return a valid bytecode dump you can feed to
  157. luadec which will produce a script.
  158. If you wondered how script decompilation worked, now you know.
  159. Bytecode conversion: Diagram
  160. Lua VM
  161. RCCService
  162. Client
  163. Deserializer
  164. Lua Function
  165. Function Call
  166. (OP_CALL)
  167. Exploit
  168. Exploit
  169. Client
  170. Server
  171. Converted Lua Bytecode
  172. Standard Lua Bytecode
  173. Alternatives to Bytecode Conversion
  174. ● Proto Conversion: Proto conversion is obtaining the intermediary format used by
  175. Lua obtained after compilation then converting it into Roblox’s intermediary
  176. format. This is very fast and is used by most script execution exploits out here,
  177. albeit it’s very insecure and can be easily patched. Just like bytecode conversion
  178. ● CLVM (Custom Lua Virtual Machine): Considered the fastest and most secure yet
  179. unstable script execution method there is. Relatively new too, but sadly hard to
  180. develop and requires a lot of manhours to get working. This method is simply
  181. making a custom Lua virtual machine that uses Roblox’s own lua state rather than
  182. yours. It works, it’s been proven to work with a certain degree of success, but
  183. maintaining the VM is quite hard and a lot of errors could occur if you don’t know
  184. what you’re doing. Despite those cons, it’s very secure and considered unpatchable
  185. by Roblox. See here.
  186. The End
  187. Cya! :P
  188. - Louka
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement