Table of Contents
Leanpub book, originally based on Blog posts
This book started with the Jni4net related blog posts published on my blog and eventually evolved into the book you have in your hands (or eReader).
The idea to use my blog posts was to:
- kickstart the creation of this book (and provide a number of chapters that could be further improved)
- capture the multiple experiments and learning curves that I experienced (while learning how to use Jni4net)
- provide a ‘real world’ point of view on how to learn and use Jni4net
The theme of this book is ‘Practical’ (hence the name ‘Practical Jni4net’), and what I am trying to do here is to show how to use these technologies in practical situations, specially how to apply them to solve real problems. This means that sometimes the end result is a bit messy, with lots of rabbit-holes/tangents followed (and un-followed). But that is how it works. When learning a new technology, what is really important is to experiment a lot, and see how it works for the problem we have at hand.
An open book, freely available at GitHub
My objective with this book is to share knowledge and to help others (as I have been helped by numerous other online resources)
If you are reading this on your eReader, please visit https://github.com/DinisCruz/Book_Practical_Jni4net for a full hyperlinked copy of the content AND (more importantly) the code samples used in the book.
This repository contains the full source materials that are used to create the version available at Leanpub which can be downloaded for free, or paid for using the dynamic ‘how much do you want to pay’ slider. These fees help to cover the costs of creating this book, so if you bought the book, THANK YOU, if you haven’t, then it would be great if you could help a bit (assuming you liked and learned from this book).
I’m also using the GitHub’s Issues (see here) to manage the work items, ideas and bugs/problems with the content/code-samples.
Please use it if you want to provide any ideas, fixes or contributions to this book.
Finally, note that this book is still in a ‘draft release status’ with lots of content and fixes to be added.
I can be contacted directly at dinis.cruz@owasp.org (note that sometimes I’m not very good with my email, so don’t be shy to resend your email/question multiple times :) )
Notes about current structure
The current version groups the posts by published month.
I’m still thinking about the best way to structure this content, and how to present it in a easy to read/consume format.
It would be great if you (the reader) could provide some feedback on the book’s structure, for example:
- if you think the book’s order should be different (or chapters renamed)
- a particular chapter is not very clear, easy-to-understand or relevant
- etc…
About the Author
Dinis Cruz is a Developer and Application Security Engineer focused on how to develop secure applications. A key drive is on ‘Automating Application Security Knowledge and Workflows’ which is the main concept behind the OWASP O2 Platform and the FluentSharp APIs.
After many years (and multiple roles) Dinis is still very active at OWASP, currently leading the OWASP O2 Platform project and helping out other projects and initiatives.
After failing to scale his own security knowledge, learned Git, created security vulnerabilities in code published to production servers, delivered training to developers, and building multiple CI (Continuous Integration) environments; Dinis had the epiphany that the key to application security is “Secure Continuous Delivery: Developer’s Immediate Connection to What They’re Creating”. This ‘Immediate Connection/Feedback’ concept is deep rooted in the development of the O2 Platform, and is something that will keep Dinis busy for many years.
Change log:
Here are the changes made (per version):
-
v0.22 (Jan 2016)
- Major improvements on editor-ui where it now renders a local site using express and markdown
- Changed intro, removed ‘Making Java, .NET and C++ apps work together’ post (which is now part of the intro)
- Major refactor and clean up of content files:
- Each month has it own folder which contains the respective images
- Checked/fixed all images, and updated links to referenced Pdfs
- All files were renamed to allow easy editing and maintenance
- Significant content fixes and refactoring
- Reached 95% book completion (waiting for feedback before marking it as complete)
-
v0.21 (Dec 2015)
- Started text refactoring in order to get better structure for book generation and book editing
-
v0.20 (April 2015)
- Setup leanpub to use Github instead of Dropbox
- updated content: Introduction
-
v0.16 (Mar 2014)
- First release of book with raw import from blogger posts (no formatting or editing done)
- Created Git repo on local dropbox sync folder
- created github repository for this book: https://github.com/DinisCruz/Book_Practical_Jni4Net
- Added this change log
Introduction
In November 2012 I found a way to make Java and .Net applications work together.
That is something that I’ve always wanted to be able to do, since it would allow the use of O2’s REPL in Java application.
The the key technology innovations that were required to make this happen were:
- 1) Side-by-site JVM/CLR execution and programming (in same process) - This is the ability provided by the amazing http://jni4net.sourceforge.net/ FOSS project which creates bridges between Java and .Net (see this research paper for the main concept between .Net/Java bridges http://views.cs.up.ac.za/vdata/Views-CCPE.pdf )
- 2) Injection of Managed/Unmanaged controls into another process’s controls/windows - This the capability of the O2 Platform that allows the easy injection of .NET dlls into other non managed process.
Note that this is still a massive hack, but it works :)
It would be great if there was a more official way to make this happen.
This book contains my Jni4Net experiments and research.
1. November 2012
- C# REPL a java process (ZAP Proxy)
- Controlling OWASP ZAP remotely (via Java BeanShell REPL in .Net)
- Writing and Invoking O2 Methods from Java and Eclipse
C# REPL a java process (ZAP Proxy)
After I discovered the Jni4Net FOSS project which provides the foundation blocks to create a Java bridge to .Net (and vice-versa).
To try Jni4Net, and see if it was really possible to have .Net and Java code running on the same process (with the CLR and JVM being able to invoke each other’s methods), I decided to see if I could connect the O2 Platform with the OWASP ZAP project (with both running on the same process)
My first step was to use the Injecting C# DLLs into Managed (C#) and Unmanaged (C++) processes O2 capabilities to inject an C# REPL into the ZAP process.
And here they are in action:

- the foreground window is the (CLR based) C# REPL
- the background window is the (JVM based) ZAP process.
After some experiments, I was able to use Jni4Net to create an mini .Net tool (based on the the Util - Java Decompiler (JAD based) v1.0.exe ) that used Jni4Net’s direct access to the JVM to show (and browse) the the currently loaded *.jar files (based on data retrieved from the JVMs ClassLoader).
For example here are some ZAP classes, and the decompiled main method:

For more details on how these PoCs were created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-1.pdf
Controlling OWASP ZAP remotely (via Java BeanShell REPL in .Net)
Once I was able to use C# REPL in java process I was able to use the ZAP BeanShell support to start controlling and manipulating ZAP’s GUI from the .Net C# REPL.
Here is an example of adding a new ‘Site’ (i.e. a TreeNode) to the main ZAP ‘Site’s window (i.e. TreeView)

For more details on how this PoC was created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-2.pdf
Writing and Invoking O2 Methods from Java and Eclipse
After using C# REPL in java process and controlling OWASP ZAP remotely, the next step was to see if we could consume (and code) the .NET APIs from Java.
And again Jni4Net really worked!
Here is a .NET WinForms control, coded and executed from the (Eclipse written) Java code:

Once we could create *.jar files, it was a small step to create an Eclipse plugin that would load up a CLR and popup a C# based Form.

Or more interestingly an C# REPL editor (running in the same process as Eclipse):

For more details on how these PoCs were created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-3.pdf
2. March 2013
- Invoking an OWASP AppSensor Java method from .NET C# REPL
- Invoking Java BeanShell from .Net CLR
- Loading OWASP ESAPI jar and its dependencies
- Getting list of Jars loaded in SystemClassLoader
- Java BeanShell REPL v1.0.exe
Invoking an OWASP AppSensor Java method from .NET C# REPL (using Jni4Net)
On the topic of AppSensor, you might find the code snippet below interesting.
Inside an O2 Platform C# REPL editor (which is running in .Net’s CLR), I was able to:
- load the AppSensor jar in a new class loader,
- access/view its classes in a GUI
- create an instance of org.owasp.appsensor.trendmonitoring.TrendEvent
- execute the getTime method
Note that the AppSensor code is running on the Java’s JVM (loaded in the same process as the .Net’s CLR)
The code is still in very rough status, but it works :)
Here (screenshot below) is what it looks like: * note the Date value in the output window (bottom right) which is the result (shown as a .NET String) of the Java getTime method * on top you have a view into the AppSensor’s classes, methods, parameters, return type * on the bottom left you can see the written C# REPL script
![CropperCapture[34]](/site_images/Practical_Jni4Net/CropperCapture_25255B34_25255D_thumb.jpg)
Here is the code:
1
//var topPanel = "{name}".popupWindow(700,400);
2
var
topPanel
=
panel
.
clear
().
add_Panel
();
3
//"".open_ConsoleOut();
4
5
var
jarToLoad
=
@"E:/_Code_Tests/_AppSensor/AppSensor-0.1.3.jar"
;
6
7
8
var
bridgeSetup
=
new
BridgeSetup
(){
Verbose
=
true
};
9
10
var
jniAction
=
new
API_Jni4Net_Active
();
11
12
//bridgeSetup.AddClassPath(jarToLoad);
13
//return "here";
14
try
15
{
16
Bridge
.
CreateJVM
(
bridgeSetup
);
17
}
18
catch
(
System
.
Exception
ex
)
19
{
20
ex
.
log
();
21
return
"error"
;
22
}
23
24
var
jniEnv
=
JNIEnv
.
ThreadEnv
;
25
26
//calculate list of classes in Jar file
27
var
jarFile
=
Class
.
forName
(
"java.util.jar.JarFile"
)
28
.
getConstructor
(
new
java
.
lang
.
Class
[]
{
java
.
lang
.
String
.
_class
})
29
.
newInstance
(
new
java
.
lang
.
Object
[]
{
jniEnv
.
NewString
(
jarToLoad
)
});
30
31
var
entries
=
jarFile
.
getClass
().
getMethod
(
"entries"
,
null
)
32
.
invoke
(
jarFile
,
null
);
33
var
hasMoreElements
=
entries
.
getClass
().
getMethod
(
"hasMoreElements"
,
null
);
34
var
nextElement
=
entries
.
getClass
().
getMethod
(
"nextElement"
,
null
);
35
var
classesInJar
=
new
List
<
string
>();
36
while
((
bool
)(
java
.
lang
.
Boolean
)
hasMoreElements
.
invoke
(
entries
,
null
))
37
{
38
var
path
=
nextElement
.
invoke
(
entries
,
null
).
str
();
39
if
(
path
.
ends
(
".class"
))
40
classesInJar
.
add
(
path
.
remove
(
".class"
).
replace
(
"/"
,
"."
));
41
}
42
43
//Get class loader for Jar
44
45
46
var
jarToLoad_asUrl
=
new
java
.
io
.
File
(
jarToLoad
).
toURL
();
47
var
servletApi_asUrl
=
new
java
.
io
.
File
(
@"E:\_Code_Tests\_AppSensor\servlet-api.jar"
).
toURL
();
48
49
//var url = new java.net.URL(jarToLoad);
50
51
var
urlArray
=
jniEnv
.
NewObjectArray
(
2
,
java
.
net
.
URL
.
_class
,
null
);
52
jniEnv
.
SetObjectArrayElement
(
urlArray
,
0
,
jarToLoad_asUrl
);
53
jniEnv
.
SetObjectArrayElement
(
urlArray
,
1
,
servletApi_asUrl
);
54
55
var
urlClassLoaderClass
=
java
.
lang
.
Class
.
forName
(
"java.net.URLClassLoader"
);
56
57
var
ctor
=
urlClassLoaderClass
.
getConstructors
()[
2
];
58
var
systemClassLoader
=
ClassLoader
.
getSystemClassLoader
();
59
var
urlClassLoader
=
(
ClassLoader
)
ctor
.
newInstance
(
new
java
.
lang
.
Object
[]
{
urlArray
,
systemC
\
60
lassLoader
});
61
62
63
//var appSensorClass = urlClassLoader.loadClass("org.owasp.appsensor.APPSENSOR");
64
//var appSensorClass = urlClassLoader.loadClass("org.owasp.appsensor.trendmonitoring.referenc\
65
e
.
InMemoryTrendDataStore
$
1
");
66
67
foreach
(
var
classInJar
in
classesInJar
)
68
{
69
try
70
{
71
urlClassLoader
.
loadClass
(
classInJar
);
72
"Loaded class: {0}"
.
info
(
classInJar
);
73
}
74
catch
(
System
.
Exception
ex
)
75
{
76
"Failed to load {0} due to {1}"
.
error
(
classInJar
,
ex
.
Message
);
77
}
78
}
79
80
var
treeView
=
topPanel
.
add_TreeView
().
java_SetTreeView_To_Show_Jni4Net_Reflection_Data
();
81
var
loadedClasses
=
jniAction
.
java_From_ClassLoader_get_Loaded_Classes
(
urlClassLoader
);
82
treeView
.
add_Nodes
(
loadedClasses
,
(
@class
)=>
@class
.
getName
(),
true
);
83
84
//invoke a method from AppSensor
85
var
trendEvent
=
urlClassLoader
.
loadClass
(
"org.owasp.appsensor.trendmonitoring.TrendEvent"
).
g
\
86
etConstructors
().
first
()
87
.
newInstance
(
new
java
.
lang
.
Object
[]
{
new
Date
(),
88
jniEnv
.
NewString
(
"1"
),
89
jniEnv
.
NewString
(
"aaa"
),
90
jniEnv
.
NewString
(
"ccc"
)
})
;
91
return
trendEvent
.
getClass
()
92
.
getMethod
(
"getTime"
,
null
).
invoke
(
trendEvent
,
null
)
93
.
str
();
94
95
96
//return loadedClasses;
97
/*
98
//Get JavaProperties from the loaded JVM
99
Properties javaSystemProperties = java.lang.System.getProperties();
100
foreach (java.lang.String key in Adapt.Enumeration(javaSystemProperties.keys()))
101
"key: {0}".info(key);
102
return javaSystemProperties;
103
*/
104
return
"ok"
;
105
//using java.io;
106
//using java.lang;
107
//using java.util;
108
//using net.sf.jni4net;
109
//using net.sf.jni4net.jni
110
//using net.sf.jni4net.adaptors;
111
//O2Ref:Jni4Net/lib/jni4net.n-0.8.6.0.dll
112
113
//O2File:API_Jni4Net_Active.cs
note: this code sample was running on the x64 version of the O2 Platform (because the default JavaHome in my dev VM points to a x64 Java version)
Invoking Java BeanShell from .Net CLR
Here is a very rough PoC of how I was able to execute a JavaBean shell script from inside the O2 Platform (with the java code executed under a JVM)
Executing “return 2+2;” as a java beanshell comand (see result on the bottom right Output pane)

1
var
jni4Net
=
new
API_Jni4Net
();
2
jni4Net
.
setUpBride
();
3
4
var
beanShellJar
=
"http://www.beanshell.org/bsh-2.0b4.jar"
.
uri
().
download
(
false
);
5
var
_string
=
JNIEnv
.
ThreadEnv
.
NewString
(
"return 2+2; "
);
6
var
interpreter_Class
=
beanShellJar
.
java_Jar_Class
(
"bsh.Interpreter"
);
7
8
var
interpreter
=
interpreter_Class
.
newInstance
();
9
var
result
=
interpreter
.
java_Invoke_UsingSignature
(
"eval"
,
"(Ljava/lang/String;)Ljava/lang/Ob\
10
ject
;
",_string);
11
return
result
.
toString
();
12
13
return
beanShellJar
.
java_Jar_Classes
();
14
15
//using net.sf.jni4net.jni;
16
//using java.lang;
17
//using java.net;
18
//O2File:API_Jni4Net.cs
19
//O2Ref:jni4net.n-0.8.6.0.dll
Loading OWASP ESAPI jar and its dependencies
Here is a pretty cool PoC where I was able to load an jar file and its dependencies into an ‘Jni4Net created’ JVM
Using the system class loader
This is the ESAPI class we want to load (the code below returns null)
1
new
API_Jni4Net
().
setUpBride
();
2
return
"org.owasp.esapi.util.ObjFactory"
.
java_Class
();
Using the technique shown in Adding files to java classpath at runtime - Stack Overflow , we can add the esapi jar into the sysLoader class path
1
new
API_Jni4Net
().
setUpBride
();
2
3
var
esapiJar
=
@"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar"
;
4
var
classLoader
=
ClassLoader
.
getSystemClassLoader
();
5
var
addUrl
=
classLoader
.
getClass
().
getSuperclass
().
getDeclaredMethod
(
"addURL"
,
new
Class
[]{
U
\
6
RL
.
_class
});
7
addUrl
.
setAccessible
(
true
);
8
addUrl
.
invoke
(
classLoader
,
new
java
.
lang
.
Object
[]{
esapiJar
.
java_File
().
toURL
()
});
9
10
return
"org.owasp.esapi.util.ObjFactory"
.
java_Class
();
11
12
//using net.sf.jni4net.jni;
13
//using java.lang;
14
//using java.net;
15
//O2File:API_Jni4Net.cs
16
//O2Ref:jni4net.n-0.8.6.0.dll
which will now work:

If we now try to load all classes in the ESAPI jar, we will get 172 classes and a number of class load errors (due to missing jars references)

Let’s refactor the code and create the addJarToSystemClassLoader method

And load one of the dependencies (note the increased number of classes loaded (183)):

And now if we load all jars in the libs folder (all 30 of them), we will get 197 classes and no load errors

Here are the jars added to the classpath:

Here is the code (shown above) that loaded all esapi classes into the system class path:
1
new
API_Jni4Net
().
setUpBride
();
2
3
var
classLoader
=
ClassLoader
.
getSystemClassLoader
();
4
5
Action
<
string
>
addJarToSystemClassLoader
=
6
(
pathToJar
)=>{
7
var
addUrl
=
classLoader
.
getClass
()
8
.
getSuperclass
()
9
.
getDeclaredMethod
(
"addURL"
,
new
Class
[]{
URL
.
_cla
\
10
ss
});
11
addUrl
.
setAccessible
(
true
);
12
addUrl
.
invoke
(
classLoader
,
new
java
.
lang
.
Object
[]{
pathToJar
.
java_File
().
\
13
toURL
()
});
14
};
15
16
var
esapiJar
=
@"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar"
;
17
var
esapiLibs
=
@"E:\_Code_Tests\ESAPI\libs"
;
18
19
addJarToSystemClassLoader
(
esapiJar
);
20
foreach
(
var
jarFile
in
esapiLibs
.
files
(
"*.jar"
))
21
addJarToSystemClassLoader
(
jarFile
);
22
23
var
classesInJar
=
esapiJar
.
java_Jar_Classes_Names
();
24
return
classLoader
.
loadClasses
(
classesInJar
).
size
();
25
26
//using net.sf.jni4net.jni;
27
//using java.lang;
28
//using java.net;
29
//O2File:API_Jni4Net.cs
30
//O2Ref:jni4net.n-0.8.6.0.dll
Once these classes are loaded we can use the tool shown in C# REPL a java process (ZAP Proxy) to browse them and view its source code:

We can now create instances of ESAPI using reflection.
One problem to solve is the need to define where the ESAPI.properties file is:
1
new
API_Jni4Net
().
setUpBride
();
2
var
classLoader
=
ClassLoader
.
getSystemClassLoader
();
3
4
var
arrayList
=
"java.util.ArrayList"
.
java_Class
().
newInstance
();
5
6
return
"org.owasp.esapi.reference.DefaultSecurityConfiguration"
.
java_Class
().
newInstance
();
7
8
var
easpi
=
"org.owasp.esapi.ESAPI"
.
java_Class
();
9
return
easpi
.
getMethod
(
"encoder"
,
null
).
invoke
(
null
,
null
);
10
return
easpi
.
newInstance
().
typeFullName
();
The code above will throw an error on line 439 of the DefaultSecurityConfiguration file

which is:

Using a separate class loader
Here is a script that loads 172 classes from the ESAPI jar
1
var
jni4Net
=
new
API_Jni4Net
();
2
jni4Net
.
setUpBride
();
3
4
var
esapiJar
=
@"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar"
;
5
var
classLoader
=
(
new
URL
[]
{
esapiJar
.
java_File
().
toURL
()
}).
java_ClassLoader_forJars
();
6
7
return
classLoader
.
loadClasses
(
esapiJar
.
java_Jar_Classes_Names
()).
size
();
8
9
//using net.sf.jni4net.jni;
10
//using java.lang;
11
//using java.net;
12
//O2File:API_Jni4Net.cs
13
//O2Ref:jni4net.n-0.8.6.0.dll
This version will load 183 classes since we are also loading the servlet-api
1
var
jni4Net
=
new
API_Jni4Net
();
2
jni4Net
.
setUpBride
();
3
var
servletApi
=
@"E:\_Code_Tests\ESAPI\libs\servlet-api-2.4.jar"
;
4
var
esapiJar
=
@"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar"
;
5
var
classLoader
=
(
new
URL
[]
{
esapiJar
.
java_File
().
toURL
()
,
servletApi
.
java_File
().
toURL
()
}
\
6
).
java_ClassLoader_forJars
();
7
8
return
classLoader
.
loadClasses
(
esapiJar
.
java_Jar_Classes_Names
()).
size
();
9
//using net.sf.jni4net.jni;
10
//using java.lang;
11
//using java.net;
12
//O2File:API_Jni4Net.cs
13
//O2Ref:jni4net.n-0.8.6.0.dll
Getting list of Jars loaded in SystemClassLoader
I just created a couple extension methods for Jni4Net that allow (amongst other things) the listing of the jars currently loaded in the SystemClassLoader (see API_Jni4Net.cs for the code of these .NET Extension Methods)
The objective is to simplify the use of Jni4Net, and to hide the complexity in consuming Java code from .NET.
Here are a couple examples of these Extension Methods in action:
When you create a simple Jni4Net bridge there is only one jar loader:

Next lets load a jar dynamically and see it appear in the list of loaded jars

Note that once the jar is loaded we can access its classes:

Create instances and invoke methods:

Here is the script show above:
1
var
jni4Net
=
new
API_Jni4Net
().
setUpBride
();
2
var
env
=
jni4Net
.
jniEnv
;
3
4
var
classLoader
=
ClassLoader
.
getSystemClassLoader
();
5
var
beanShellJar
=
"http://www.beanshell.org/bsh-2.0b4.jar"
.
uri
().
download
(
false
);
6
7
classLoader
.
loadJar
(
beanShellJar
);
8
var
interpreter_Class
=
beanShellJar
.
java_Jar_Class
(
"bsh.Interpreter"
);
9
10
return
interpreter_Class
.
newInstance
()
11
.
java_Invoke_UsingSignature
(
"eval"
,
12
"(Ljava/lang/String;)Ljava/lang/Object;"
,
\
13
14
"return \"hello from java: \" + (2 + 2); "
15
.
java_String
()
16
).
str
();
17
18
return
classLoader
.
jarsInClassPath
();
19
//using java.lang;
20
//O2File:API_Jni4Net.cs
21
//O2Ref:jni4net.n-0.8.6.0.dll
Finally we can also load/add to the system class path, entire folders with jars. For example all ESAPI dependencies:

Java BeanShell REPL v1.0.exe
Using the technique shown in Invoking Java BeanShell from .Net CLR, here is REPL that allows the quick execution of Java BeanShell command in a C# GUI
You can download this stand-alone O2 tool from: Util - Jni4Net - Java BeanShell REPL v1.0.exe
This is what the default GUI looks like:

If you expand the Console Out panel, you can see the Jni4Net initialization messages:

There are a number of code samples included:

Which will be auto executed on selection:

This one for example:

will create a Java button:

which of course can be modified and executed:

Also included is a REPL menu

That allows the scripting of the current Form:

like for example: changing its title and making all controls pink

or inject a WebBrowser (on the left) with the Jni4Net website:

The other REPL menu item:

Allows the scripting and visualization of the Jni4Net object:

For reference here is the script (also available at O2.Platform.Scripts\3rdPartyJni4NetUtil - Jni4Net - Java BeanShell REPL.h2) that created this GUI (a bit messy and in need for a good dose of refactoring)):
1
O2Setup
.
extractEmbededConfigZips
();
2
3
//Set value of Bridge.homeDir
4
var
jni4NetDir
=
PublicDI
.
config
.
ToolsOrApis
.
pathCombine
(
@"Jni4Net\lib"
);
5
var
fieldInfo
=
(
FieldInfo
)
typeof
(
Bridge
).
field
(
"homeDir"
);
6
PublicDI
.
reflection
.
setField
(
fieldInfo
,
jni4NetDir
);
7
//return typeof(Bridge).fieldValue("homeDir");
8
9
"jni4net.j-0.8.6.0.jar location: {0}"
.
info
(
Bridge
.
FindJar
());
10
11
//stand-alone tool not working (not finding the "jni4net.j-0.8.6.0.jar");
12
13
//"jni4net.n-0.8.6.0.dll is at: {0}".info("jni4net.n-0.8.6.0.dll".assembly_Location());
14
var
topPanel
=
"Util - JavaBean REPL - {0}"
.
format
(
clr
.
details
()).
popupWindow
(
800
,
400
)
15
.
insert_LogViewer
();
16
//var topPanel = panel.clear().add_Panel();
17
18
Action
execute
=
null
;
19
20
var
replGui
=
topPanel
.
add_REPL_Gui
();
21
replGui
.
On_ExecuteCode
=
()=>
execute
();
22
23
replGui
.
Output_Panel
.
insert_Below
(
"Console Out"
).
add_ConsoleOut
();
24
25
"test console out"
.
console_WriteLine
();
26
27
var
codeText
=
replGui
.
Code_Panel
.
add_SourceCodeViewer
();
28
var
toolStrip
=
topPanel
.
insert_Above_ToolStrip
()
29
.
add_Button
(
"Run"
,
"btExecuteSelectedMethod_Image"
.
formImage
(),()=>
e
\
30
xecute
())
31
.
toolStrip
();
32
var
samplesMenu
=
toolStrip
.
add_DropDown
(
"Java BeanShell Code Samples"
,
"help_browser"
.
formIm
\
33
age
());
34
var
beanShellJar
=
"http://www.beanshell.org/bsh-2.0b4.jar"
.
uri
().
download
(
false
);
35
//configure Jni4Net bridge and BeanShell
36
"Configuring Jnu4Net"
.
info
();
37
var
jni4Net
=
new
API_Jni4Net
();
38
jni4Net
.
setUpBride
();
39
"Default Jni4Net bridge setup "
.
info
();
40
41
var
interpreterClass
=
beanShellJar
.
java_Jar_Class
(
"bsh.Interpreter"
);
42
if
(
interpreterClass
.
isNull
()
&&
clr
.
x86
())
// most likely means it couldn't find a compatible\
43
44
{
45
var
javaHomeLocation
=
@"C:\Program Files (x86)\Java\jre7"
;
46
"interpretreClass was null, and this is a 32bit process, so to set-up bridge with JavaHom\
47
e
:
{
0
}
".error(javaHomeLocation);
48
var
bridgeSetup
=
new
BridgeSetup
()
{
JavaHome
=
javaHomeLocation
};
49
jni4Net
.
setUpBride
(
bridgeSetup
);
50
interpreterClass
=
beanShellJar
.
java_Jar_Class
(
"bsh.Interpreter"
);
51
}
52
var
interpreter
=
interpreterClass
.
ctor
();
53
54
if
(
interpreter
.
isNull
())
55
{
56
"Failed to create interpreter instance"
.
error
();
57
}
58
59
java
.
lang
.
System
.
@out
.
println
(
"Hello Java world!"
);
60
61
//set execute method
62
execute
=
63
()=>{
64
var
code
=
codeText
.
get_Text
().
java_String
();
65
try
66
{
67
var
result
=
interpreter
.
java_Invoke_UsingSignature
(
"eval"
,
"(Ljava/lang/String;)L\
68
java
/
lang
/
Object
;
",code);
69
replGui
.
showOutput
(
result
.
str
());
70
}
71
catch
(
System
.
Exception
ex
)
72
{
73
ex
.
log
(
"Execution error"
);
74
replGui
.
showErrorMessage
(
ex
.
Message
);
75
}
76
};
77
Action
<
string
,
string
>
addCodeSample
=
78
(
title
,
codeSample
)=>
samplesMenu
.
add_Button
(
title
,
79
()=>{
80
codeText
.
set_Text
(
codeSample
);
81
execute
();
82
});
83
Func
<
string
>
getJni4NetReplCode
=
84
()=>{
85
return
"return jni4Net.bridgeSetup;"
.
line
().
line
()
+
86
"//O2Ref:jni4net.n-0.8.6.0.dll"
.
line
()
+
87
"//O2Ref:{0}"
.
format
(
jni4Net
.
type
().
Assembly
.
ManifestModule
.
str
());
88
};
89
90
91
toolStrip
.
add_DropDown
(
"REPL"
,
"text_x_script"
.
formImage
())
92
.
add_Button
(
"REPL Form"
,
()=>
topPanel
.
parentForm
().
script_Me
(
"form"
))
93
.
add_Button
(
"REPL Jni4Net"
,
()=>
jni4Net
.
script_Me
(
"jni4Net"
).
set_Code
(
getJni4NetRep
\
94
lCode
()))
95
.
add_Button
(
"REPL Jni4Net Assembly"
,
()=>
jni4Net
.
type
().
Assembly
.
script_Me
(
"assembl\
96
y
"));
97
98
toolStrip
.
add_Button
(
"Open BeanSheel website"
,
"internet_web_browser"
.
formImage
(),
99
()=>
"http://www.beanshell.org/"
.
startProcess
())
100
.
add_Button
(
"View Jni4Net O2 Blog posts"
,
"internet_web_browser"
.
formImage
(),
101
()=>
"http://blog.diniscruz.com/search/label/Jni4Net"
.
startProcess
\
102
());
103
104
//Code samples
105
106
addCodeSample
(
"Hello World"
,
"return \"Hello World (from java bean)\";"
);
107
addCodeSample
(
"Java Properties"
,
"return java.lang.System.getProperties();"
);
108
109
addCodeSample
(
"Int sums"
,
110
@"int a = 12;
111
return a + 30;"
);
112
113
addCodeSample
(
"Hashtable and date"
,
114
@"Hashtable hashtable = new Hashtable();
115
Date date = new Date();
116
hashtable.put( ""today"", date );
117
return hashtable.get(""today"");"
);
118
119
120
addCodeSample
(
"Create java button"
,
121
@"button = new JButton( ""My Button"" );
122
frame = new JFrame( ""My Frame"" );
123
frame.getContentPane().add( button, ""Center"" );
124
frame.pack();
125
frame.setVisible(true);
126
127
return ""You should have a Java button"" +
128
""somewhere on your screen"";"
);
129
130
131
addCodeSample
(
"System.out.println (not working)"
,
132
@"java.lang.System.out.println(""Hello Java world!"");
133
return ""done"";"
);
134
135
samplesMenu
.
items
().
first
()
136
.
PerformClick
();
137
138
replGui
.
Execute_Button
.
click
();
139
replGui
.
Output_Panel
.
splitterDistance
(
50
);
140
141
return
"done"
;
142
143
144
//using System.Reflection
145
//using net.sf.jni4net
146
//using net.sf.jni4net.jni;
147
//using java.lang;
148
//using java.net;
149
//O2File:API_Jni4Net.cs
150
//O2Ref:Jni4Net\lib\jni4net.n-0.8.6.0.dll
151
//O2Embed:java.ico
152
//O2EmbedTool:Jni4Net
3. May 2013
- First execution of ESAPI.jar Encoder methods from O2’s C# REPL
First execution of ESAPI.jar Encoder methods from O2’s C# REPL
In April 2013 (when preparing to do the OWASP AppSensor and O2 Platform at Security B-Sides London workshop with colin), I achieved something that I have been trying to do for a while:
- Use the O2 Platform’s C# REPL environment to programatically access (in real time) the ESAPI jar apis and methods.
- Consume AppSensor’s jar directly from a .NET app (in that case TeamMentor)
When I was integrating AppSensor (java) with TeamMentor (.NET) I needed to solve the the problem described in Loading OWASP ESAPI jar and its dependencies from C# since AppSensor has an hard dependency on ESAPI (i.e. without ESAPI, AppSensor doesn’t work)
After a bit of research and coding, here is the first code sample that shows ESAPI being consumed from O2 (via Jni4Net)

Note how the ESAPI Encoder’s encodeForHTML method is being executed:

And displayed in the Output window:

To to clarify, although this code is being triggered and executed from a .Net GUI and CLR, the actual code that is doing the encoding is the one from http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encoder.html which is running running on a JVM inside the same process as the CLR (the magic sauce is provided by the amazing Jni4Net)
For example here is the execution result of the ESAPI Encoder’s encodeForJavascript:

Which is exactly what I wanted :)
I wonder if we can also execute the current ESAPI unit test the same way? For example, now that we have the capability to see what the encodings output of the Java version of ESAPI looks like, we can try to compare it with the ESAPI .NET methods (since they should match right?)
Here is code sample shown in above:
1
var
jni4Net
=
new
API_Jni4Net
();
2
jni4Net
.
setUpBride
();
3
var
jarPath
=
@"E:\_Code_Tests\OWASP_AppSensor\_O2_Test"
;
4
var
jars
=
jarPath
.
files
(
"*.jar"
);
5
6
7
var
classLoader
=
jni4Net
.
systemClassLoader
().
loadJars
(
jars
);
8
var
esapi
=
classLoader
.
loadClass
(
"org.owasp.esapi.ESAPI"
);
9
var
encoder
=
esapi
.
getMethod
(
"encoder"
,
null
).
invoke
(
null
,
null
);
10
11
12
return
encoder
.
getClass
().
getMethod
(
"encodeForJavaScript"
,
new
Class
[]
{
java
.
lang
.
String
.
_clas
\
13
s
}
)
14
.
invoke
(
encoder
,
new
java
.
lang
.
Object
[]
{
"aaa<h1>bbb<h1>"
.
java_String
()});
15
16
//using net.sf.jni4net.jni;
17
//using java.lang;
18
//using java.net;
19
//O2File:API_Jni4Net.cs
20
//O2Ref:jni4net.n-0.8.6.0.dll
Here is the current folder set-up and jars loaded:

A key to make it work is the fact that the ESAPI.properties file is in the same path as the ESAPI.jar
4. June 2013
- Another step in the use of ESAPI and AppSensor Jars from .Net/C#
Another step in the use of ESAPI and AppSensor Jars from .Net/C
At the OWASP EU Tour London Chapter event meeting I presented the next step of my research on using ESAPI and AppSensor inside a .NET application like TeamMentor (using Jni4Net to allow the JVM to work side by side with the CLR).
The source code of the demo I presented is posted to the github.com:DinisCruz/TeamMentor_3_3_AppSensor repo, and this post shows a number of screenshots of what is in there.
I used TeamMentor’s TBot C# and AngularJS pages to create the prototypes (since it is very easy and fast to code in that enviroment)
The pages were added to the main TBot ** control panel, in 3 new sections: **AppSensor, AppSensor/ESAPI and AppSensor/JVM:

Let’s look at all of them and see what they do.
Java Properties
Shows the Properties of the current JVM, and is a good first script to run (since it shows that the Jni4Net CLR to JVM bridge is correctly set up)

Jars In Class Path
This one shows the Jar’s currently loaded and some details about the loaded classes

The image above shows that there is only one jar loaded at start (jni4net.j-0.8.6.0.jar) and below is what it looks after the Setup AppSensor Tbot page is executed

Setup AppSensor
This will load up the AppSensor Jars and perform a simple test to see if one of the expected classes can be loaded

View ESAPI Encodings
Once we have the ESAPI loaded we can open up this page that shows what all the ESAPI encodings looks like


Note how many they are: encodeForHTML , encodeForHTMLAttribute, encodeForCSS, encodeForJavascript, encodeForVBScript, encodeForLDAP, encodeForDN, encodeForXPath, encodeForXML, encodeForXmlAttribute, encodeForURL you can use this GUI to try out what a specific encoding looks like.
For example change the text on the left and click on of the ‘encodeFor…‘ buttons

AppSensor Logs
Shows the currently registered logs

To help to create a new log entry, this page provides a link to:
Create AppSensor Exception
which looks like this:

This page (for testing) allows the use of the ex querystring parameter to create a new AppSensor log message

and clicking on View AppSensor Logs, which show details of the log:

5. August 2013
- Consuming a forked version of Jni4Net
- Compiling Jni4Net from Source
- Fixing the ‘Attempted to read or write protected memory’ issue
Consuming a forked version of Jni4Net
An O2 user was having some issues with my Jni4Net scripts, and after some research, I realized that the problem existed inside the current published jni4net.n-0.8.6.0.dll:

The problem is that with the 0.8.6 version we get an ‘Attempted to read or write protected memory’ error when trying to connect to an existing Java process we previously injected O2 into.
The solution is to use the latest version of Jni4Net, which is not available for direct download, but its code it at: http://jni4net.googlecode.com/svn jni4Net
After getting the compilation and generation process right (see Dealing with ‘Attempted to read or write protected memory), I had this folder:

I was then able to write these scripts (which worked):
1) start ZAP and inject O2 into the new process:

1
var
apiZap
=
new
API_Zap
();
2
apiZap
.
Launch
();
3
var
process
=
apiZap
.
ZapProcess
;
4
process
.
waitFor_MainWindowHandle
();
5
var
o2Injector
=
new
API_O2_Injector
();
6
o2Injector
.
injectIntoProcess
(
process
,
false
,
true
);
7
8
//using OWASP
9
//O2File:API_Zap.cs
10
//O2File:API_O2_Injector.cs
11
//using O2.XRules.Database.APIs
2) hook VisualStudio to that process (assumes there is only one java.exe process)

1
var
visualStudio
=
new
VisualStudio_2010
();
2
var
processes
=
visualStudio
.
dte
().
Debugger
.
LocalProcesses
;
3
Func
<
string
,
EnvDTE
.
Process
>
findProcess
=
4
(
name
)=>{
5
foreach
(
EnvDTE
.
Process
process
in
processes
)
//linq doesn't work here
6
if
(
process
.
Name
.
contains
(
name
))
7
return
process
;
8
return
null
;
9
};
10
EnvDTE
.
Process
targetProcess
=
findProcess
(
"java.exe"
);
11
targetProcess
.
Attach
();
12
return
targetProcess
;
3) create bridge and output java properties (inside the ZAP REPL)

1
Environment
.
SetEnvironmentVariable
(
"JAVA_HOME"
,
@"C:\Program Files (x86)\Java\jre7"
);
2
Bridge
.
CreateJVM
(
new
BridgeSetup
(){
Verbose
=
true
});
3
4
Properties
javaSystemProperties
=
java
.
lang
.
System
.
getProperties
();
5
6
foreach
(
java
.
lang
.
String
key
in
Adapt
.
Enumeration
(
javaSystemProperties
.
keys
()))
7
8
"key: {0}"
.
info
(
key
);
9
10
//using java.io;
11
//using java.lang;
12
//using java.util;
13
//using net.sf.jni4net;
14
//using net.sf.jni4net.adaptors;
15
//O2Ref:E:\O2\_Source_Code\test\jni4net\jni4net\target\jni4net-0.8.7.0-bin\lib\jni4net.n-0.8.\
16
7.0
.
dll
4) Executed PoC - Jni4Net - Classes, Methods, Fields in target.h2 script (inside ZAP process)

which listed all loaded java classes (and its decompiled code):

To make this work (and deal with the ‘Attempted to read or write protected memory’ prob) I had to copy the jni4net.j-0.8.7.0.jar to the ZAP default class path and manually skip a bit of code when connected to VisualStudio

Compiling Jni4Net from Source
After using the git svn clone -s http://jni4net.googlecode.com/svn jni4Net command, to create a local clone of the SVN repo:

I started by opening the jni4net.sln file in VS 2010.
But on first compile I had this error:

which was created by the missing selvin.exportdllattribute-0.2.6.0.dll

which looks like should be here:

let’s take a look at the v0-8-generics branch

Since it is also not there, I just downloaded it from:

… and saved it to:

… and updated the references

Now the code compiles, but we get this error:

… which is caused by this post build command:

… and is resolved by downloading this file:

… into this folder:

I was able to get it to compile by changing the selvin.exportdll-0.2.6.0.exe to selvin.exportdll-0.2.5.0.exe (couldn’t find the 0.2.6.0 version)

Next there was a bunch of NUnit errors, which were resolved using

Now we have a clean compilation (with only a bunch of warnings)

But, they all fail to execute:

This was a good sign that I should look for a readme.txt, which I found in the repo root (ie. RTFM when everything else fails :) )

From that file I got the clue to run the loadTools.cmd script:

… which downloads the missing files into the lib folder:

Since we now have the 0.2.6.0 versions, I updated back the VS solution (and removed the nUnit package from Nuget)
Then I executed

… and

… this took a while, and although most looked ok:

… the last one failed:

That said, it looked like the required files seemed to have been created:

And the Unit tests now pass:

I didn’t like the fact that we had that build error, so I tracked the problem to a missing NUnit installation:

Since I’m on a x64 VM and the path is hard-coded in the Maven script, I had to copy the installed nunit files into the expected folder:

… which didn’t work

The problem was caused by the fact that I’m currently using an x64 JDK:

Forcing a x86 (32bit) version of the JDK will do the trick

Since the tests expect to find Nunit in the (x86) folder:

We need to rename the NUnit-2.5.8 folder to the expected value:

Finally we have a successful complete build:

… with all created files placed inside the target folder:

Fixing the ‘Attempted to read or write protected memory’ issue
This error happened when running a java process (like ZAP):

…with the O2 Platform REPL injected into:

… and executing PoC - Jni4Net - List JavaProperties.h2 scrit, resulted in an unmanaged error (which is always a worse case scenario in the .NET Interop world)

As the (simpler script shows), the error happens on the CreateJVM invocation

My next step was to create a local build of Jni4Net (see Compiling Jni4Net from Source) and to use it to attach into an existing running ZAP with an O2 REPL injected.
Here is the moment when I have VisualStudio hooked, the script compiled (in the ZAP REPL), the jni4net dll loaded (with Symbols) in VisualStudio and a breakpoint on the CreateJVM method:

Here is where I think the problem exists:

The args object (created via JNI) seems to be empty.
It is then assigned to the value of the Jni4Net class path string

The args object is used here:

And inside that method, if I let args to be used, we will get the ‘Attempted to read or write protected memory’ error

But, if I change the execution path (manually) and set it to the line below (where no args is passed)

Then the execution will be ok (note that the path with the &initArgs would had thrown an ‘Attempted to read or write protected memory’ by now):

The only problem with this approach (which is basically not adding the classpath clue to the current JVM) is that unless we manually add the jni4net jar to the target app, we will get an exception here:

i.e. br.handle would be 0 (meaning that the net.sf.jnin4net.Bridge class could not be found)
To fix it, I added the Patch_IgnoreArgsInAttach property

… which is then used here (to allow the selection of the path that works)

I also changed the assembly name (so it is easy to track its use):

After the compilation I copied it to the main target folder:

To test it , I used the script

… to start ZAP with a REPL, where I could execute OK:

Final step is to create a zip of the bin folder

Put it on a public available location like DropBox
Update the installer API to use that version:

Update the API_Jni4Net.cs to use the jni4net.n-0.8.7.0_Patched.dll assembly (as seen below on first compile the referenced will be downloaded)

… once the compilation works:

I was able to to run Jni4Net in the main O2 Platform process

…and on the ‘injected into’ java processes:

Pushing changes to GitHub
Once the fix was working ok I added a remote to the local repo:

… push it

… and confirm that the commits I did locally (with the patch)

… where pushed successfully:
