[英]Windows CredEnumerate in JNA
我正在嘗試使用 JNA 讀取存儲在 Windows 憑據管理器(控制面板 > 憑據管理器)中的憑據。 找到了它的 c 函數( CredEnumerateW ),它似乎運行正常,因為它返回“true”,並且我能夠獲取存儲在憑據管理器中的憑據數量(在我的代碼中為 pCount.getValue())。
問題是我不知道如何讀取憑據數據。 保存憑據的結構( _CREDENTIAL )在內部包含其他 2 個結構(FILETIME 和 CREDENTIAL_ATTRIBUTE)。 我試圖搜索類似的示例,但找不到與我的場景相符的示例。 請在下面查看我的代碼。
有人可以幫我解決這個問題嗎?
public class CredEnumerate {
/*
typedef struct _CREDENTIAL {
DWORD Flags;
DWORD Type;
LPTSTR TargetName;
LPTSTR Comment;
FILETIME LastWritten;
DWORD CredentialBlobSize;
LPBYTE CredentialBlob;
DWORD Persist;
DWORD AttributeCount;
PCREDENTIAL_ATTRIBUTE Attributes;
LPTSTR TargetAlias;
LPTSTR UserName;
} CREDENTIAL, *PCREDENTIAL; */
public static class _CREDENTIAL extends Structure {
public int Flags;
public int Type;
public String TargetName;
public String Comment;
public _FILETIME LastWritten = new _FILETIME();
public int CredentialBlobSize;
public byte CredentialBlob;
public int Persist;
public int AttributeCount;
public _CREDENTIAL_ATTRIBUTE Attributes = new _CREDENTIAL_ATTRIBUTE();
public String TargetAlias;
public String UserName;
}
/*
typedef struct _CREDENTIAL_ATTRIBUTE {
LPTSTR Keyword;
DWORD Flags;
DWORD ValueSize;
LPBYTE Value;
} CREDENTIAL_ATTRIBUTE, *PCREDENTIAL_ATTRIBUTE; */
public static class _CREDENTIAL_ATTRIBUTE extends Structure {
public String Keyword;
public int Flags;
public int ValueSize;
public byte Value;
}
/*
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME; */
public static class _FILETIME extends Structure {
public int dwLowDateTime;
public int dwHighDateTime;
}
/*
BOOL CredEnumerate(
_In_ LPCTSTR Filter,
_In_ DWORD Flags,
_Out_ DWORD *Count,
_Out_ PCREDENTIAL **Credentials) */
public interface Advapi32 extends StdCallLibrary {
Advapi32 INSTANCE = (Advapi32) Native.loadLibrary("advapi32", Advapi32.class);
boolean CredEnumerateW(String filter, int flags, IntByReference count, PointerByReference pref);
}
public static void main(String[] args) {
IntByReference pCount = new IntByReference();
PointerByReference pCredentials = new PointerByReference();
boolean result = Advapi32.INSTANCE.CredEnumerateW(null, 0, pCount, pCredentials);
System.out.println("result: " + result);
System.out.println("number of credentials: " + pCount.getValue());
//how to read the _CREDENTIAL structure data from pCredentials?
}
}
結果對我來說,指針數組,也就是指向指針的指針,是使用 CredEnumerate 的唯一棘手的事情。 這是用 p.getPointerArray 解決的。
用 Win32 函數 CredEnumerateW 的聲明
boolean CredEnumerateW(WString Filter, int Flags, IntByReference Count, // int ref
PointerByReference pptr);
我的解決方案如下:
try {
IntByReference count = new IntByReference();
PointerByReference pptr = new PointerByReference();
boolean ok = WinCrypt.INSTANCE.CredEnumerateW(null, WinCrypt.Enumerate.CRED_ENUMERATE_ALL_CREDENTIALS,
count, pptr);
System.out.println("count: " + count.getValue());
CREDENTIAL[] credentials = new CREDENTIAL[count.getValue()];
Pointer p = pptr.getValue();
Pointer[] credPointers = p.getPointerArray(0, count.getValue());
for (int i = 0; i < count.getValue(); i++) {
CREDENTIAL cred = new CREDENTIAL(credPointers[i]);
credentials[i] = cred;
String tnameEncoded = cred.targetName.toString();
String namespace = tnameEncoded.substring(0, tnameEncoded.indexOf(":"));
String attributeAndTargetName = tnameEncoded.substring(tnameEncoded.indexOf(":") + 1);
String targetName = attributeAndTargetName.substring(attributeAndTargetName.indexOf("=") + 1);
System.out.println(namespace + " / " + targetName);
if (namespace.indexOf("MicrosoftAccount") < 0 && namespace.indexOf("WindowsLive") < 0) {
CREDENTIAL fullcred = readCredentials(targetName, getType(namespace), 0);
System.out.println(" " + cred.userName);
System.out.println(" " + fullcred.getPassword());
}
}
} catch (LastErrorException error) {
int rc = error.getErrorCode();
String errMsg = error.getMessage();
System.out.println(rc + ": " + errMsg);
System.exit(1);
}
並從指針地址讀取憑據實現為
private static CREDENTIAL readCredentials(String targetName, int type, int flags)
throws UnsupportedEncodingException {
try {
PointerByReference pptr = new PointerByReference();
boolean ok = WinCrypt.INSTANCE.CredReadW(new WString(targetName), type, flags, pptr);
CREDENTIAL cred = new CREDENTIAL(pptr.getValue());
return (cred);
} catch (LastErrorException error) {
int rc = error.getErrorCode();
String errMsg = error.getMessage();
System.out.println(rc + ": " + errMsg);
throw new IllegalAccessError("cannot access windows vault for " + targetName);
}
}
另請參閱如何在 JNA 中映射 Windows API CredWrite/CredRead? 有關使用 Win32 憑據 API 讀取/寫入憑據的基礎知識。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.