`
gh_fisher
  • 浏览: 8990 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Java通过JNI调用EXE导出函数

阅读更多

此文解决的是使用Eclipse,通过JNI,调用DLL文件。再通过该DLL文件,使用GetProcAddress调用EXE文件的导出函数。

目前只能做到调用单一的函数。

下一步可扩展的:

1.       连续调用多个函数,并组合使用。

2.       EXE运行过程中。动态的调用导出函数并获取实时的数据。

3.       通过强制破解,调用非导出的函数。

 

A.Eclipse下创建java项目。创建包:com。创建java类:Helloworld

代码如下:

//包名在生成头文件时容易出问题。应当注意java头文件全名包括包名。
package com;

public class Helloworld {
	/**
	 * 此处载入DLL。DLL中必须实现所有native方法。否则会出现错误。
	 * load和loadLibrary不同处在于:load是指向具体文件全名,包括路径和后缀名。这对跨平台有影响。
	 * loadLibrary是指向资源文件。针对不同平台(windows是DLL)。java会搜寻环境里所有的路径,查找符合条件的资源文件。
	 * 具体路径列表包括系统环境配置里的路径 > 项目所在路径。
	 */
	static {
		System.out.println(System.getProperty("java.library.path"));//打印系统环境变量
		System.loadLibrary("Helloworld");
	}
	
	/**
	 * 声明native的displayHelloworld方法。以备DLL中实现。
	 * 须注意传入参数和返回参数的类型。
	 */
	public native int displayHelloWorld(int testInt);

	public static void main(String[] args) {
		try {
			Helloworld hw = new Helloworld();
			System.out.println("测试开始");
			int j = hw.displayHelloWorld(99);//调用native方法。此时java会追踪本地资源的具体实现方法。
			System.out.println(j);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

B.编译该java文件,生成Helloworld.class文件。

C.在命令行使用javah命令调用Helloworld.class生成头文件。Javah提示如下:

C:\Users\“用户名”>javah
用法:javah [选项] <类>

其中 [选项] 包括:

-help 输出此帮助消息并退出
-classpath <路径> 用于装入类的路径
-bootclasspath <路径> 用于装入引导类的路径
-d <目录> 输出目录
-o <文件> 输出文件(只能使用 -d 或 -o 中的一个)
-jni 生成 JNI样式的头文件(默认)
-version 输出版本信息
-verbose 启用详细输出
-force 始终写入输出文件

使用全限定名称指定 <类>(例
如,java.lang.Object)。

 根据项目具体路径。输入命令如例:

C:\Users\“用户名”>javah –classpath D:\Workspaces\MyEclipse\DLLTest\bin –d D:\Workspaces\MyEclipse\DLLTest\ -jni com.Helloworld

com.Helloworld 为包名加“.”加class文件名。

运行后目标文件com_Helloworld.h会在指定目录生成。

用编辑工具打开后,代码如下:

 

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

#ifndef _Included_com_Helloworld
#define _Included_com_Helloworld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_Helloworld
 * Method:    displayHelloWorld
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_com_Helloworld_displayHelloWorld
  (JNIEnv *, jobject, jint);

#ifdef __cplusplus
}
#endif
#endif

此头文件的作用是连接javaC++。文件路径与DLL的文件路径保持一致,与Java项目路径无关。

它将作为中转DLL的头文件,中转DLL将实现头文件中的JNICALL Java_com_Helloworld_displayHelloWorld方法。

D.创建基于C++EXE项目。VC2008中的创建方法如下:

1.       文件>新建>项目。

2.       选择类型Win32>Win32项目。并输入项目名如:Hello。位置随意。

3.       点击确定成功后,在新窗口点击下一步选择windows应用程序,选中空项目。

4.       创建主CPP文件:Hello.cpp。代码如下:

#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;

int i = 20;

extern "C" __declspec(dllexport) int returnAdd(int j) //__declspec(dllexport)代表此函数为导出函数。
{
	return ++j;
}

int main()
{
	cout << returnAdd(i) << endl;
	system("pause");
	return 0;
}

5.       编译并测试,结果如下图:

名为Hello.exe文件就创建完成。此文件作为被测试的EXE文件。文件位置随意。

E.创建基于C++DLL项目。VC2008中的创建方法如下:

1.       文件>新建>项目。

2.       按下图选择类型Win32>Win32项目。并输入项目名如:Helloworld。位置随意。

 

 

 

 

 

3.       点击确定成功后,在新窗口点击下一步选择DLL,选中空项目后如图:

 

4.       点击完成。生成空的DLL项目。配置该DLL项目环境。如下图:在项目上点击右键,选择属性。

选择配置属性>常规>输出目录。如下图:单击下拉按钮,选择java项目路径。

选择配置属性>常规>C/C++。如下图:单击下拉按钮,选择java项目路径,JDK目录下的Include文件夹和win32文件夹。如下下图。

在资源文件上点右键>添加>现有项。选择java生成的头文件。

5. 依次创建头文件:stdafx.h

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // 从Windows 头中排除极少使用的资料
// Windows 头文件:
#include <windows.h>



// TODO: 在此处引用程序需要的其他头文件

 targetver.h

#pragma once

// 以下宏定义要求的最低平台。要求的最低平台
// 是具有运行应用程序所需功能的Windows、Internet Explorer 等产品的
// 最早版本。通过在指定版本及更低版本的平台上启用所有可用的功能,宏可以
// 正常工作。

// 如果必须要针对低于以下指定版本的平台,请修改下列定义。
// 有关不同平台对应值的最新信息,请参考MSDN。
#ifndef WINVER                          // 指定要求的最低平台是Windows Vista。
#define WINVER 0x0600           // 将此值更改为相应的值,以适用于Windows 的其他版本。
#endif

#ifndef _WIN32_WINNT            // 指定要求的最低平台是Windows Vista。
#define _WIN32_WINNT 0x0600     // 将此值更改为相应的值,以适用于Windows 的其他版本。
#endif

#ifndef _WIN32_WINDOWS          // 指定要求的最低平台是Windows 98。
#define _WIN32_WINDOWS 0x0410 // 将此值更改为适当的值,以适用于Windows Me 或更高版本。
#endif

#ifndef _WIN32_IE                       // 指定要求的最低平台是Internet Explorer 7.0。
#define _WIN32_IE 0x0700        // 将此值更改为相应的值,以适用于IE 的其他版本。
#endif

 创建CPP主文件:Helloworld.cpp

#include "stdio.h"       
#include "jni.h"//导入JNI头文件。该文件在JDK目录下的include文件里。
#include "com_Helloworld.h"//导入java生成的头文件。
#include "stdafx.h"

JNIEXPORT jint JNICALL Java_com_Helloworld_displayHelloWorld(JNIEnv *, jobject, jint j)
{
	typedef DWORD (CALLBACK* LPFNEXEFUNC)(DWORD);//定义exe文件中导出函数的指针类型。返回值为DWORD,参数为DWORD。

	int i = j;//定义一个返回变量并赋初值。

	printf("尝试获取Instance\n");

	HINSTANCE hInstance =::LoadLibrary(TEXT("D:\\work\\VS2008\\Projects\\Hello\\Debug\\Hello.exe"));//导入目标EXE文件。导入方法与导入DLL一致。注意路径需要转换格式。

	printf("获取Instance完毕\n");
    
	if (hInstance != NULL)
	{
		printf("尝试获取方法指针\n");

		LPFNEXEFUNC returnadd = (LPFNEXEFUNC)::GetProcAddress(hInstance, "returnAdd");
		
		if (!returnadd)
		{
			printf("获取方法指针失败\n");
			// handle the error
			FreeLibrary(hInstance);
			i = 0;			
		}
		else
		{
			printf("获取方法指针成功\n");

			i = (int)returnadd(i);

			printf("方法执行完毕\n");

			FreeProcInstance(returnadd);
			FreeLibrary(hInstance);

			printf("Handle释放完毕\n");
		}
	}
	else
	{
		printf("Instance为空\n");
	}
	return i;
}
//$(SolutionDir)$(ConfigurationName) 输出目录

6.       单击F7编辑。如果成功,在java项目的路径下会生成5个文件。其中包括一个DLL文件。如下图:

 

 

 

 

 

 

 

 

 

F.Eclipse下执行java项目(如果遇到错误点击忽略)。可以看到如下结果:

改变传入的值。重新运行java项目即可获取相应的结果。

分享到:
评论

相关推荐

    JNI技术手册 c/c++调用java

    3) 在C工程Cpro下建立hello.def文件(用于定义导出的函数),内容为: 40 4) 在C工程Cpro下建立makefile文件,内容为: 40 5) Make Targets 40 6) Make Targets视图下双击step1,在C工程Cpro下生成hello.o 文件。 41...

    java开源包5

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包1

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    JAVA上百实例源码以及开源项目源代码

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    JAVA上百实例源码以及开源项目

    5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...

    java开源包4

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包101

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包11

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包6

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包9

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包8

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包10

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包3

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包2

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    java开源包7

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

    Java资源包01

    JCarder 是一个用来查找多线程应用程序中一些潜在的死锁,通过对 Java 字节码的动态分析来完成死锁分析。 Java的Flash解析、生成器 jActionScript jActionScript 是一个使用了 JavaSWF2 的 Flash 解析器和生成器。...

Global site tag (gtag.js) - Google Analytics