此文解決的是使用 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 提示如下:
用法:javah [選項] <類>
其中 [選項] 包括:
-help 輸出此幫助消息并退出
-classpath <路徑> 用于裝入類的路徑
-bootclasspath <路徑> 用于裝入引導類的路徑
-d <目錄> 輸出目錄
-o <文件> 輸出文件(只能使用 -d 或 -o 中的一個)
-jni 生成 JNI樣式的頭文件(默認)
-version 輸出版本信息
-verbose 啟用詳細輸出
-force 始終寫入輸出文件
使用全限定名稱指定 <類>(例
如,java.lang.Object)。
? 根據項目具體路徑。輸入命令如例:
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
此頭文件的作用是連接 java 與 C++ 。文件路徑與 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"http://導入JNI頭文件。該文件在JDK目錄下的include文件里。 #include "com_Helloworld.h"http://導入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 項目即可獲取相應的結果。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
