Skip to content

Instantly share code, notes, and snippets.

@exhuma
Forked from mrh1997/wincred.py
Last active September 2, 2024 15:57
Show Gist options
  • Select an option

  • Save exhuma/a310f927d878b3e5646dc67dfa509b42 to your computer and use it in GitHub Desktop.

Select an option

Save exhuma/a310f927d878b3e5646dc67dfa509b42 to your computer and use it in GitHub Desktop.

Revisions

  1. @RodneyRichardson RodneyRichardson revised this gist Jul 21, 2021. 1 changed file with 25 additions and 15 deletions.
    40 changes: 25 additions & 15 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -14,12 +14,13 @@
    else:
    print('No matching credentials found')
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    Based on https://gist.github.com/exhuma/a310f927d878b3e5646dc67dfa509b42
    which was based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import NamedTuple, Optional
    import ctypes as ct
    import ctypes.wintypes as wt
    from enum import Enum
    from typing import NamedTuple, Optional

    LPBYTE = ct.POINTER(wt.BYTE)

    @@ -42,9 +43,8 @@ def as_pointer(cls):

    class CredType(Enum):
    """
    Enumeration for different credential types.
    See https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentiala
    CRED_TYPE_* enumeration (wincred.h)
    https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw
    """
    GENERIC = 0x01
    DOMAIN_PASSWORD = 0x02
    @@ -58,6 +58,10 @@ class CredType(Enum):

    @as_pointer
    class CredentialAttribute(ct.Structure):
    """
    PCREDENTIAL_ATTRIBUTEW structure (wincred.h)
    https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credential_attributew
    """
    _fields_ = [
    ('Keyword', wt.LPWSTR),
    ('Flags', wt.DWORD),
    @@ -67,6 +71,10 @@ class CredentialAttribute(ct.Structure):

    @as_pointer
    class WinCredential(ct.Structure):
    """
    CREDENTIALW structure (wincred.h)
    https://docs.microsoft.com/en-us/windows/win32/api/wincred/ns-wincred-credentialw
    """
    _fields_ = [
    ('Flags', wt.DWORD),
    ('Type', wt.DWORD),
    @@ -91,19 +99,21 @@ def get_generic_credential(name: str) -> Optional[Credential]:
    :param name: The lookup string for the credential.
    """
    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, WinCredential]
    advapi32.CredReadW.restype = wt.BOOL
    advapi32.CredReadW.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, ct.POINTER(WinCredential)]

    cred_ptr = WinCredential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, ct.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
    password_as_list = [int.from_bytes(cred_blob[pos:pos+2], 'little')
    for pos in range(0, cred_blob_size, 2)]
    password = ''.join(map(chr, password_as_list))
    advapi32.CredFree(cred_ptr)
    return Credential(username, password)
    try:
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
    password_as_list = [int.from_bytes(cred_blob[pos:pos+2], 'little')
    for pos in range(0, cred_blob_size, 2)]
    password = ''.join(map(chr, password_as_list))
    return Credential(username, password)
    finally:
    advapi32.CredFree(cred_ptr)
    return None


  2. exhuma revised this gist Jun 25, 2019. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,19 @@
    """
    Access windows credentials
    Credentials must be stored in the Windows Credentials Manager in the Control
    Panel. This helper will search for "generic credentials" under the section
    "Windows Credentials"
    Example usage::
    result = get_generic_credential('foobar')
    if result:
    print("NAME:", result.username)
    print("PASSWORD:", result.password)
    else:
    print('No matching credentials found')
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import NamedTuple, Optional
  3. exhuma revised this gist Jun 25, 2019. 1 changed file with 14 additions and 9 deletions.
    23 changes: 14 additions & 9 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import NamedTuple
    from typing import NamedTuple, Optional
    import ctypes as ct
    import ctypes.wintypes as wt
    from enum import Enum
    @@ -69,10 +69,13 @@ class WinCredential(ct.Structure):
    ('UserName', wt.LPWSTR)]


    def get_generic_credential(name: str) -> Credential:
    def get_generic_credential(name: str) -> Optional[Credential]:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    Returns a tuple of name and password of a generic Windows credential.
    If no matching credential is found, this will return ``None``
    :param name: The lookup string for the credential.
    """
    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    @@ -88,14 +91,16 @@ def get_generic_credential(name: str) -> Credential:
    password = ''.join(map(chr, password_as_list))
    advapi32.CredFree(cred_ptr)
    return Credential(username, password)
    else:
    raise IOError("Failure reading credential")
    return None


    def main():
    name, pwd = get_generic_credential('foobar')
    print("GITHUB NAME:", name)
    print("GITHUB PASSWORD:", pwd)
    result = get_generic_credential('foobar')
    if result:
    print("NAME:", result.username)
    print("PASSWORD:", result.password)
    else:
    print('No matching credentials found')


    if __name__ == '__main__':
  4. exhuma revised this gist Jun 25, 2019. 1 changed file with 11 additions and 6 deletions.
    17 changes: 11 additions & 6 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -3,13 +3,18 @@
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import Tuple
    from typing import NamedTuple
    import ctypes as ct
    import ctypes.wintypes as wt
    from enum import Enum

    LPBYTE = ct.POINTER(wt.BYTE)

    Credential = NamedTuple('Credential', [
    ('username', str),
    ('password', str)
    ])


    def as_pointer(cls):
    """
    @@ -48,7 +53,7 @@ class CredentialAttribute(ct.Structure):


    @as_pointer
    class Credential(ct.Structure):
    class WinCredential(ct.Structure):
    _fields_ = [
    ('Flags', wt.DWORD),
    ('Type', wt.DWORD),
    @@ -64,16 +69,16 @@ class Credential(ct.Structure):
    ('UserName', wt.LPWSTR)]


    def get_generic_credential(name: str) -> Tuple[str, str]:
    def get_generic_credential(name: str) -> Credential:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, Credential]
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, WinCredential]

    cred_ptr = Credential()
    cred_ptr = WinCredential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, ct.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    @@ -82,7 +87,7 @@ def get_generic_credential(name: str) -> Tuple[str, str]:
    for pos in range(0, cred_blob_size, 2)]
    password = ''.join(map(chr, password_as_list))
    advapi32.CredFree(cred_ptr)
    return username, password
    return Credential(username, password)
    else:
    raise IOError("Failure reading credential")

  5. exhuma revised this gist Jun 25, 2019. 1 changed file with 4 additions and 5 deletions.
    9 changes: 4 additions & 5 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -64,16 +64,15 @@ class Credential(ct.Structure):
    ('UserName', wt.LPWSTR)]


    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, Credential]


    def get_generic_credential(name: str) -> Tuple[str, str]:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, Credential]

    cred_ptr = Credential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, ct.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
  6. exhuma revised this gist Jun 25, 2019. 1 changed file with 16 additions and 9 deletions.
    25 changes: 16 additions & 9 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -11,6 +11,17 @@
    LPBYTE = ct.POINTER(wt.BYTE)


    def as_pointer(cls):
    """
    Class decorator which converts the class to ta ctypes pointer
    :param cls: The class to decorate
    :return: The class as pointer
    """
    output = ct.POINTER(cls)
    return output


    class CredType(Enum):
    """
    Enumeration for different credential types.
    @@ -27,6 +38,7 @@ class CredType(Enum):
    MAXIMUM_EX = MAXIMUM + 1000


    @as_pointer
    class CredentialAttribute(ct.Structure):
    _fields_ = [
    ('Keyword', wt.LPWSTR),
    @@ -35,9 +47,7 @@ class CredentialAttribute(ct.Structure):
    ('Value', LPBYTE)]


    PCredentialAttribute = ct.POINTER(CredentialAttribute)


    @as_pointer
    class Credential(ct.Structure):
    _fields_ = [
    ('Flags', wt.DWORD),
    @@ -49,25 +59,22 @@ class Credential(ct.Structure):
    ('CredentialBlob', LPBYTE),
    ('Persist', wt.DWORD),
    ('AttributeCount', wt.DWORD),
    ('Attributes', PCredentialAttribute),
    ('Attributes', CredentialAttribute),
    ('TargetAlias', wt.LPWSTR),
    ('UserName', wt.LPWSTR)]


    PCredential = ct.POINTER(Credential)


    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, ct.POINTER(PCredential)]
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, Credential]


    def get_generic_credential(name: str) -> Tuple[str, str]:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    cred_ptr = PCredential()
    cred_ptr = Credential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, ct.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
  7. exhuma revised this gist Jun 25, 2019. 1 changed file with 24 additions and 24 deletions.
    48 changes: 24 additions & 24 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -4,11 +4,11 @@
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import Tuple
    import ctypes as CT
    import ctypes.wintypes as WT
    import ctypes as ct
    import ctypes.wintypes as wt
    from enum import Enum

    LPBYTE = CT.POINTER(WT.BYTE)
    LPBYTE = ct.POINTER(wt.BYTE)


    class CredType(Enum):
    @@ -27,39 +27,39 @@ class CredType(Enum):
    MAXIMUM_EX = MAXIMUM + 1000


    class CredentialAttribute(CT.Structure):
    class CredentialAttribute(ct.Structure):
    _fields_ = [
    ('Keyword', WT.LPWSTR),
    ('Flags', WT.DWORD),
    ('ValueSize', WT.DWORD),
    ('Keyword', wt.LPWSTR),
    ('Flags', wt.DWORD),
    ('ValueSize', wt.DWORD),
    ('Value', LPBYTE)]


    PCredentialAttribute = CT.POINTER(CredentialAttribute)
    PCredentialAttribute = ct.POINTER(CredentialAttribute)


    class Credential(CT.Structure):
    class Credential(ct.Structure):
    _fields_ = [
    ('Flags', WT.DWORD),
    ('Type', WT.DWORD),
    ('TargetName', WT.LPWSTR),
    ('Comment', WT.LPWSTR),
    ('LastWritten', WT.FILETIME),
    ('CredentialBlobSize', WT.DWORD),
    ('Flags', wt.DWORD),
    ('Type', wt.DWORD),
    ('TargetName', wt.LPWSTR),
    ('Comment', wt.LPWSTR),
    ('LastWritten', wt.FILETIME),
    ('CredentialBlobSize', wt.DWORD),
    ('CredentialBlob', LPBYTE),
    ('Persist', WT.DWORD),
    ('AttributeCount', WT.DWORD),
    ('Persist', wt.DWORD),
    ('AttributeCount', wt.DWORD),
    ('Attributes', PCredentialAttribute),
    ('TargetAlias', WT.LPWSTR),
    ('UserName', WT.LPWSTR)]
    ('TargetAlias', wt.LPWSTR),
    ('UserName', wt.LPWSTR)]


    PCredential = CT.POINTER(Credential)
    PCredential = ct.POINTER(Credential)


    advapi32 = CT.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = WT.BOOL
    advapi32.CredReadA.argtypes = [WT.LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCredential)]
    advapi32 = ct.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = wt.BOOL
    advapi32.CredReadA.argtypes = [wt.LPCWSTR, wt.DWORD, wt.DWORD, ct.POINTER(PCredential)]


    def get_generic_credential(name: str) -> Tuple[str, str]:
    @@ -68,7 +68,7 @@ def get_generic_credential(name: str) -> Tuple[str, str]:
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    cred_ptr = PCredential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, CT.byref(cred_ptr)):
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, ct.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
  8. exhuma revised this gist Jun 25, 2019. 1 changed file with 14 additions and 10 deletions.
    24 changes: 14 additions & 10 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -27,16 +27,18 @@ class CredType(Enum):
    MAXIMUM_EX = MAXIMUM + 1000


    class CREDENTIAL_ATTRIBUTE(CT.Structure):
    class CredentialAttribute(CT.Structure):
    _fields_ = [
    ('Keyword', WT.LPWSTR),
    ('Flags', WT.DWORD),
    ('ValueSize', WT.DWORD),
    ('Value', LPBYTE)]
    PCREDENTIAL_ATTRIBUTE = CT.POINTER(CREDENTIAL_ATTRIBUTE)


    class CREDENTIAL(CT.Structure):
    PCredentialAttribute = CT.POINTER(CredentialAttribute)


    class Credential(CT.Structure):
    _fields_ = [
    ('Flags', WT.DWORD),
    ('Type', WT.DWORD),
    @@ -47,29 +49,31 @@ class CREDENTIAL(CT.Structure):
    ('CredentialBlob', LPBYTE),
    ('Persist', WT.DWORD),
    ('AttributeCount', WT.DWORD),
    ('Attributes', PCREDENTIAL_ATTRIBUTE),
    ('Attributes', PCredentialAttribute),
    ('TargetAlias', WT.LPWSTR),
    ('UserName', WT.LPWSTR)]
    PCREDENTIAL = CT.POINTER(CREDENTIAL)


    PCredential = CT.POINTER(Credential)


    advapi32 = CT.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = WT.BOOL
    advapi32.CredReadA.argtypes = [WT.LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]
    advapi32.CredReadA.argtypes = [WT.LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCredential)]


    def GetGenericCredential(name:str) -> Tuple[str, str]:
    def get_generic_credential(name: str) -> Tuple[str, str]:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    cred_ptr = PCREDENTIAL()
    cred_ptr = PCredential()
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, CT.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
    password_as_list = [int.from_bytes(cred_blob[pos:pos+2], 'little')
    for pos in range(0, cred_blob_size, 2)]
    for pos in range(0, cred_blob_size, 2)]
    password = ''.join(map(chr, password_as_list))
    advapi32.CredFree(cred_ptr)
    return username, password
    @@ -78,7 +82,7 @@ def GetGenericCredential(name:str) -> Tuple[str, str]:


    def main():
    name, pwd = GetGenericCredential('git:https://github.com')
    name, pwd = get_generic_credential('foobar')
    print("GITHUB NAME:", name)
    print("GITHUB PASSWORD:", pwd)

  9. exhuma revised this gist Jun 25, 2019. 1 changed file with 11 additions and 9 deletions.
    20 changes: 11 additions & 9 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,8 @@
    import ctypes.wintypes as WT
    from enum import Enum

    LPBYTE = CT.POINTER(WT.BYTE)


    class CredType(Enum):
    """
    @@ -25,35 +27,35 @@ class CredType(Enum):
    MAXIMUM_EX = MAXIMUM + 1000


    LPBYTE = CT.POINTER(WT.BYTE)
    LPWSTR = WT.LPWSTR
    LPCWSTR = WT.LPWSTR
    class CREDENTIAL_ATTRIBUTE(CT.Structure):
    _fields_ = [
    ('Keyword', LPWSTR),
    ('Keyword', WT.LPWSTR),
    ('Flags', WT.DWORD),
    ('ValueSize', WT.DWORD),
    ('Value', LPBYTE)]
    PCREDENTIAL_ATTRIBUTE = CT.POINTER(CREDENTIAL_ATTRIBUTE)


    class CREDENTIAL(CT.Structure):
    _fields_ = [
    ('Flags', WT.DWORD),
    ('Type', WT.DWORD),
    ('TargetName', LPWSTR),
    ('Comment', LPWSTR),
    ('TargetName', WT.LPWSTR),
    ('Comment', WT.LPWSTR),
    ('LastWritten', WT.FILETIME),
    ('CredentialBlobSize', WT.DWORD),
    ('CredentialBlob', LPBYTE),
    ('Persist', WT.DWORD),
    ('AttributeCount', WT.DWORD),
    ('Attributes', PCREDENTIAL_ATTRIBUTE),
    ('TargetAlias', LPWSTR),
    ('UserName', LPWSTR)]
    ('TargetAlias', WT.LPWSTR),
    ('UserName', WT.LPWSTR)]
    PCREDENTIAL = CT.POINTER(CREDENTIAL)


    advapi32 = CT.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = WT.BOOL
    advapi32.CredReadA.argtypes = [LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]
    advapi32.CredReadA.argtypes = [WT.LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]


    def GetGenericCredential(name:str) -> Tuple[str, str]:
  10. exhuma revised this gist Jun 25, 2019. 1 changed file with 21 additions and 4 deletions.
    25 changes: 21 additions & 4 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,29 @@
    #!python3
    """
    Access windows credentials
    Based on https://gist.github.com/mrh1997/717b14f5783b49ca14310419fa7f03f6
    """
    from typing import Tuple
    import ctypes as CT
    import ctypes.wintypes as WT
    from enum import Enum


    class CredType(Enum):
    """
    Enumeration for different credential types.
    See https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentiala
    """
    GENERIC = 0x01
    DOMAIN_PASSWORD = 0x02
    DOMAIN_CERTIFICATE = 0x03
    DOMAIN_VISIBLE_PASSWORD = 0x04
    GENERIC_CERTIFICATE = 0x05
    DOMAIN_EXTENDED = 0x06
    MAXIMUM = 0x07
    MAXIMUM_EX = MAXIMUM + 1000

    CRED_TYPE_GENERIC = 0x01

    LPBYTE = CT.POINTER(WT.BYTE)
    LPWSTR = WT.LPWSTR
    @@ -45,7 +62,7 @@ def GetGenericCredential(name:str) -> Tuple[str, str]:
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    cred_ptr = PCREDENTIAL()
    if advapi32.CredReadW(name, CRED_TYPE_GENERIC, 0, CT.byref(cred_ptr)):
    if advapi32.CredReadW(name, CredType.GENERIC.value, 0, CT.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
    @@ -65,4 +82,4 @@ def main():


    if __name__ == '__main__':
    main()
    main()
  11. @mrh1997 mrh1997 revised this gist Jun 24, 2019. 1 changed file with 34 additions and 17 deletions.
    51 changes: 34 additions & 17 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,19 @@
    #!python3
    """
    Access windows credentials
    """

    from typing import Tuple
    import ctypes as CT
    import ctypes.wintypes as WT

    CRED_TYPE_GENERIC = 0x01

    LPBYTE = CT.POINTER(WT.BYTE)
    LPTSTR = WT.LPSTR
    LPCTSTR = WT.LPSTR
    LPWSTR = WT.LPWSTR
    LPCWSTR = WT.LPWSTR
    class CREDENTIAL_ATTRIBUTE(CT.Structure):
    _fields_ = [
    ('Keyword', LPTSTR),
    ('Keyword', LPWSTR),
    ('Flags', WT.DWORD),
    ('ValueSize', WT.DWORD),
    ('Value', LPBYTE)]
    @@ -21,31 +22,47 @@ class CREDENTIAL(CT.Structure):
    _fields_ = [
    ('Flags', WT.DWORD),
    ('Type', WT.DWORD),
    ('TargetName', LPTSTR),
    ('Comment', LPTSTR),
    ('TargetName', LPWSTR),
    ('Comment', LPWSTR),
    ('LastWritten', WT.FILETIME),
    ('CredentialBlobSize', WT.DWORD),
    ('CredentialBlob', LPBYTE),
    ('Persist', WT.DWORD),
    ('AttributeCount', WT.DWORD),
    ('Attributes', PCREDENTIAL_ATTRIBUTE),
    ('TargetAlias', LPTSTR),
    ('UserName', LPTSTR)]
    ('TargetAlias', LPWSTR),
    ('UserName', LPWSTR)]
    PCREDENTIAL = CT.POINTER(CREDENTIAL)

    advapi32 = CT.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = WT.BOOL
    advapi32.CredReadA.argtypes = [LPCTSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]
    advapi32.CredReadA.argtypes = [LPCWSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]


    def GetPassword(url):
    credPtr = PCREDENTIAL()
    if advapi32.CredReadA(url, CRED_TYPE_GENERIC, 0, CT.byref(credPtr)):
    username = credPtr.contents.UserName
    passwordSize = credPtr.contents.CredentialBlobSize
    unicodePassword = credPtr.contents.CredentialBlob[:passwordSize:2]
    password = ''.join(map(chr, unicodePassword))
    advapi32.CredFree(credPtr)
    def GetGenericCredential(name:str) -> Tuple[str, str]:
    """
    Returns a Tuple of Name and Password of a Generic Windows Credential
    Uses bytes in Py3 and str in Py2 for url, name and password.
    """
    cred_ptr = PCREDENTIAL()
    if advapi32.CredReadW(name, CRED_TYPE_GENERIC, 0, CT.byref(cred_ptr)):
    username = cred_ptr.contents.UserName
    cred_blob = cred_ptr.contents.CredentialBlob
    cred_blob_size = cred_ptr.contents.CredentialBlobSize
    password_as_list = [int.from_bytes(cred_blob[pos:pos+2], 'little')
    for pos in range(0, cred_blob_size, 2)]
    password = ''.join(map(chr, password_as_list))
    advapi32.CredFree(cred_ptr)
    return username, password
    else:
    raise IOError("Failure reading credential")


    def main():
    name, pwd = GetGenericCredential('git:https://github.com')
    print("GITHUB NAME:", name)
    print("GITHUB PASSWORD:", pwd)


    if __name__ == '__main__':
    main()
  12. @mrh1997 mrh1997 revised this gist Sep 13, 2016. No changes.
  13. @mrh1997 mrh1997 created this gist Sep 13, 2016.
    51 changes: 51 additions & 0 deletions wincred.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    """
    Access windows credentials
    """

    import ctypes as CT
    import ctypes.wintypes as WT

    CRED_TYPE_GENERIC = 0x01

    LPBYTE = CT.POINTER(WT.BYTE)
    LPTSTR = WT.LPSTR
    LPCTSTR = WT.LPSTR
    class CREDENTIAL_ATTRIBUTE(CT.Structure):
    _fields_ = [
    ('Keyword', LPTSTR),
    ('Flags', WT.DWORD),
    ('ValueSize', WT.DWORD),
    ('Value', LPBYTE)]
    PCREDENTIAL_ATTRIBUTE = CT.POINTER(CREDENTIAL_ATTRIBUTE)
    class CREDENTIAL(CT.Structure):
    _fields_ = [
    ('Flags', WT.DWORD),
    ('Type', WT.DWORD),
    ('TargetName', LPTSTR),
    ('Comment', LPTSTR),
    ('LastWritten', WT.FILETIME),
    ('CredentialBlobSize', WT.DWORD),
    ('CredentialBlob', LPBYTE),
    ('Persist', WT.DWORD),
    ('AttributeCount', WT.DWORD),
    ('Attributes', PCREDENTIAL_ATTRIBUTE),
    ('TargetAlias', LPTSTR),
    ('UserName', LPTSTR)]
    PCREDENTIAL = CT.POINTER(CREDENTIAL)

    advapi32 = CT.WinDLL('Advapi32.dll')
    advapi32.CredReadA.restype = WT.BOOL
    advapi32.CredReadA.argtypes = [LPCTSTR, WT.DWORD, WT.DWORD, CT.POINTER(PCREDENTIAL)]


    def GetPassword(url):
    credPtr = PCREDENTIAL()
    if advapi32.CredReadA(url, CRED_TYPE_GENERIC, 0, CT.byref(credPtr)):
    username = credPtr.contents.UserName
    passwordSize = credPtr.contents.CredentialBlobSize
    unicodePassword = credPtr.contents.CredentialBlob[:passwordSize:2]
    password = ''.join(map(chr, unicodePassword))
    advapi32.CredFree(credPtr)
    return username, password
    else:
    raise IOError("Failure reading credential")