Skip to content

Instantly share code, notes, and snippets.

@rednaxelafx
Created March 26, 2011 08:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save rednaxelafx/888122 to your computer and use it in GitHub Desktop.
Save rednaxelafx/888122 to your computer and use it in GitHub Desktop.
Hack HotSpot's interpreter with return stack shellcode. Requires JRuby and BiteScript to build, works on WinXP 32-bit only. If run under a SecurityManager then it'll be caught and a security exception will be thrown before it wrecks havoc; it's configured
D:\sdk\jruby-1.4.0\bin>java -version
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) Client VM (build 19.0-b09, mixed mode, sharing)
D:\sdk\jruby-1.4.0\bin>jruby test_native_invoke.rb
D:\sdk\jruby-1.4.0\bin>javac TestStackOpsMain.java
D:\sdk\jruby-1.4.0\bin>java -Xint TestStackOpsMain
Greetings from generated code!
Greetings from managed code!
D:\sdk\jruby-1.4.0\bin>jruby test_stack_ops.rb
D:\sdk\jruby-1.4.0\bin>\sdk\groovy-1.7.2\bin\groovysh
Groovy Shell (1.7.2, JVM: 1.6.0_23)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------
groovy:000> Integer.toString(TestStackOps.getParam0(0x12345678), 16)
===> 12345678
groovy:000> Integer.toString(TestStackOps.getParam0(0x76543210), 16)
===> 76543210
groovy:000> Integer.toString(TestStackOps.getReturnAddress(), 16)
===> 972f45
groovy:000> Integer.toString(TestStackOps.getReturnAddress(), 16)
===> 972f45
groovy:000> TestStackOps.gotoSegv()
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000042, pid=2984, tid=5652
#
# JRE version: 6.0_23-b05
# Java VM: Java HotSpot(TM) Client VM (19.0-b09 mixed mode, sharing windows-x86
)
# Problematic frame:
# C 0x00000042
#
# An error report file with more information is saved as:
# D:\sdk\jruby-1.4.0\bin\hs_err_pid2984.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
D:\sdk\jruby-1.4.0\bin>java -version
java version "1.6.0_23"
Java(TM) SE Runtime Environment (build 1.6.0_23-b05)
Java HotSpot(TM) Client VM (build 19.0-b09, mixed mode, sharing)
D:\sdk\jruby-1.4.0\bin>jruby test_native_invoke.rb
D:\sdk\jruby-1.4.0\bin>javac TestStackOpsMain.java
D:\sdk\jruby-1.4.0\bin>java -Xint TestStackOpsMain
Greetings from generated code!
Greetings from managed code!
require 'rubygems'
require 'bitescript'
include BiteScript
MagicAccessorImpl = Java::SunReflect::MagicAccessorImpl
BiteScript.bytecode_version = JAVA1_6
builder = FileBuilder.build(__FILE__) do
public_class 'NativeCode', MagicAccessorImpl do
public_static_method :invokeVoid, [], void, byte[] do
iinc 0, 4 * 3 # adjust the pointer to the contents of the code array
9.times { pop } # let esp point to the stack slot that holds the return address
swap #
returnvoid # make the jump to the code
end
end
end
builder.generate do |filename, class_builder|
File.open(filename, 'wb') do |file|
file.write(class_builder.generate)
end
end
require 'rubygems'
require 'bitescript'
include BiteScript
MagicAccessorImpl = Java::SunReflect::MagicAccessorImpl
BiteScript.bytecode_version = JAVA1_6
builder = FileBuilder.build(__FILE__) do
public_class 'TestStackOps', MagicAccessorImpl do
public_static_method :getParam0, [], int, int do
10.times { pop } # let esp point to the stack slot that holds parameter 0
ireturn # parameter 0 now looks like the top-of-stack slot, so it gets returned
end
public_static_method :getReturnAddress, [], int do
9.times { pop } # let esp point to the stack slot that holds the return address
ireturn
end
public_static_method :gotoSegv, [], void do
9.times { pop } # let esp point to the stack slot that holds the return address
istore 0 # save the return address somewhere for later use (if any)
push_int 0x42 # overwrite the return address
returnvoid # make a jump to 0x00000042, causing a segfault
end
end
end
builder.generate do |filename, class_builder|
File.open(filename, 'wb') do |file|
file.write(class_builder.generate)
end
end
public class TestStackOpsMain {
public static void main(String[] args) {
// refer to earlier blog post, http://rednaxelafx.javaeye.com/blog/461787
byte[] code = {
// CODE SECTION
// push ebp
0x55,
// mov ebp,esp
(byte) 0x8B, (byte) 0xEC,
// push -0B ; /DevType = STD_OUTPUT_HANDLE
0x6A, (byte) 0xF5,
// mov eax,KERNEL32.GetStdHandle ; |
(byte) 0xB8, (byte) 0xD9, 0x2F, (byte) 0x81, 0x7C,
// call eax ; \GetStdHandle
(byte) 0xFF, (byte) 0xD0,
// push 0 ; /pReserved = NULL
0x6A, 0x00,
// push 0 ; |pWritten = NULL
0x6A, 0x00,
// push 1F ; |CharsToWrite = 1F (31.)
0x6A, 0x1F,
// call <&next_instruction> ; |
(byte) 0xE8, 0x00, 0x00, 0x00, 0x00,
// add dword ptr ss:[esp],10 ; |Buffer
(byte) 0x83, 0x04, 0x24, 0x10,
// push eax ; |hConsole
0x50,
// mov edx,KERNEL32.WriteConsoleA ; |
(byte) 0xBA, 0x5D, (byte) 0xCC, (byte) 0x81, (byte) 0x7C,
// call edx ; \WriteConsoleA
(byte) 0xFF, (byte) 0xD2,
// mov esp,ebp
(byte) 0x8B, (byte) 0xE5,
// pop ebp
0x5D,
// ret
(byte) 0xC3,
// DATA SECTION
// null-terminated string "Greetings from generated code!"
0x47, 0x72, 0x65, 0x65, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x21, 0x0A, 0x00
};
NativeCode.invokeVoid(code); // "Greetings from generated code!"
System.out.println("Greetings from managed code!");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment