我正在嘗試使用JNA調用Windows上的Secur32.dll中的QueryContextAttributes函數。我無法爲SECPKG_ATTR_SIZES調用獲取正確的調用。我有一個實現SECPKG_ATTR_NAMES和SECPKG_ATTR_PACKAGE_INFO的工作。因此,我認爲(着名的遺言)問題出現在結構的定義中,或者是關於調用的問題。使用JNA在QueryContextAttributes上無效的內存訪問
爲QueryContextAttributes微軟函數的定義是:
SECURITY_STATUS SEC_Entry QueryContextAttributes(
_In_ PCtxtHandle phContext,
_In_ ULONG ulAttribute,
_Out_ PVOID pBuffer
);
爲SecPkgContext_Sizes微軟結構的定義是:
typedef struct _SecPkgContext_Sizes {
ULONG cbMaxToken;
ULONG cbMaxSignature;
ULONG cbBlockSize;
ULONG cbSecurityTrailer;
} SecPkgContext_Sizes, *PSecPkgContext_Sizes;
的JNA庫(我使用的是JNA-4.2.2和JNA -platform-4.2.2)在Secur32中爲該.dll中的某些功能提供了一個實現。對於結構的定義是在: SecPkgContext_Names structure, SecPkgInfo structure,和 SecPkgContext_Sizes structure
因此,我已經定義了以下內容:
public interface ISecur32 extends Secur32 {
// get own copy of the INSTANCE variable
ISecur32 INSTANCE = (ISecur32) Native.loadLibrary("Secur32",
ISecur32.class,
W32APIOptions.UNICODE_OPTIONS);
// method definition to match
public int QueryContextAttributes(CtxtHandle phContext,
int SECPKG_ATTR,
PointerByReference pp);
//
// for the SECPKG_ATTR_NAMES call
// NOTE: this definition and invocation is working
//
public static class SecPkgContext_Names extends Structure {
public Pointer pName;
public SecPkgContext_Names(Pointer p)
{ super(p); }
@Override
protected List<?> getFieldOrder()
{ return Arrays.asList(new String[] { "pName" }); }
}
//
// for the SECPKG_ATTR_SIZES call
// NOTE: This invocation is NOT working
//
public static class SecPkgContext_SizesBis extends Structure {
public NativeLong cbMaxToken;
public NativeLong cbMaxSignature;
public NativeLong cbBlockSize;
public NativeLong cbSecurityTrailer;
public SecPkgContext_SizesBis(Pointer p)
{ super(p); }
@Override
protected List<?> getFieldOrder() {
return Arrays.asList(new String[] { "cbMaxToken", "cbMaxSignature",
"cbBlockSize", "cbSecurityTrailer"});
}
} //interface
呼叫的名稱(這是工作)是:
public static void querySecPkgAttr_Names(CtxtHandle phContext) {
final int SECPKG_ATTR_NAMES = 1;
PointerByReference pp = new PointerByReference();
int rc = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_NAMES,
pp);
if (rc != 0) {
_log.error("Error in QueryContextAttributes: {}", rc);
return;
}
Pointer p = pp.getPointer();
ISecur32.SecPkgContext_Names names = new ISecur32.SecPkgContext_Names(p);
names.read();
String name = names.pName.getWideString(0);
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
}
當我嘗試獲取大小(具體來說,我在cbMaxSignature值之後)時,我使用以下調用:
public static int querySecPkgAttr_Sizes(CtxtHandle phContext) {
final int SECPKG_ATTR_SIZES = 0; // SECPKG_ATTR_SIZES is 0
PointerByReference pp = new PointerByReference();
int res = ISecur32.INSTANCE.QueryContextAttributes(phContext,
SECPKG_ATTR_SIZES,
pp);
// NOTE: the call is succeeding, so this line is not invoked
if (res != 0) {
return new NativeLong(0);
}
// NOTE: I have also used pp.getPointer()
Pointer p = pp.getValue();
ISecur32.SecPkgContext_Sizes sizes =
new ISecur32.SecPkgContext_Sizes(p);
// THIS LINE THROWS THE Invalid Memory Access Error
sizes.read();
NativeLong maxSig = sizes.cbMaxSignature;
rc = ISecur32.INSTANCE.FreeContextBuffer(p);
_log.debug("FreeContextBuffer: {}", rc);
return maxSig.intValue();
}
使用上面的電話,我收到的異常堆棧跟蹤:
Exception in thread "main" java.lang.Error: Invalid memory access
at com.sun.jna.Native.getInt(Native Method)
at com.sun.jna.Pointer.getInt(Pointer.java:601)
at com.sun.jna.Pointer.getValue(Pointer.java:389)
at com.sun.jna.Structure.readField(Structure.java:705)
at com.sun.jna.Structure.read(Structure.java:565)
at gov.sandia.dart.sspi.Utils.querySecPkgAttr_Sizes(Utils.java:145)
如果不是的pp.getValue()
電話,我用pp.getPointer()
,我接受(試圖實例化對象的時候,我相信):
java.lang.IllegalArgumentException: Structure exceeds provided memory bounds
我不知道如何解決這個問題。
對於沒有一個完整的程序,我很抱歉,但要達到CtxtHandle所需的程度,需要通過AcquireCredentialsHandle和InitializeSecurityContext進行romp。我相信這些工作正常,因爲在InitializeSecurityContext
完成後,Kerberos票證顯示在MSLSA緩存中(可通過klist查看)。
我也看了一下解決方案Waffle,但是它並沒有在初始化循環中設置正確的標誌,也沒有實現QueryContextAttributes,也沒有實現這個函數的最終目標。
我對帖子的長度表示歉意。如果我遺漏了任何信息,請告訴我。
謝謝!
'PointerByReference.getValue()'是_always_如何檢索傳入引用中返回的結果。 'getPointer()'給你持有該值的內存的地址。 – technomage
你很可能有一個不正確的結構映射(你不提供'CtxtHandle'或'SecPkgContext_Sizes'的映射,所以我打賭錯誤在那裏)。用'-Djna.dump_memory = true'運行你的JVM,並打印結構;這將表明JNA的佈局。將其與類似的結構大小/字段對齊的本地轉儲相匹配。 – technomage
@technomage,感謝您的意見。 CtxtHandle是一個標準的JNA結構。在複製代碼時,SecPkgContext_Sizes最後在上面的代碼中以「Bis」結尾;我道歉。我找到了我在下面提出的一個解決方案,但我認爲應該有一種更優雅的方式來實現結果。感謝您花時間閱讀並評論我的問題! – KevinO