Sign in to follow this  
Followers 0
tannerli

DllCall GetNamedSecurityInfo()

9 posts in this topic

I am trying to write a programm for reading out file permissions, using GetNamedSecurityInfo() from advapi32.dll

DWORD WINAPI GetNamedSecurityInfo(

__in LPTSTR pObjectName,

__in SE_OBJECT_TYPE ObjectType,

__in SECURITY_INFORMATION SecurityInfo,

__out_opt PSID *ppsidOwner,

__out_opt PSID *ppsidGroup,

__out_opt PACL *ppDacl,

__out_opt PACL *ppSacl,

__out_opt PSECURITY_DESCRIPTOR *ppSecurityDescriptor

);

http://msdn.microsoft.com/en-us/library/aa446645%28VS.85%29.aspx <-- Complete function reference

Using the forum search i stumbled upon this topic from example script section

http://www.autoitscript.com/forum/index.php?showtopic=41050&view=findpost&p=305384&hl=getnamedsecurityinfo

Now my question:

How do i find out what parameters to pass to the function? I cannot find what datatype f.e. a "SECURITY INFORMATION" or a "PSID" is.

Even to figure out wheter the parameter ObjectType where I want to pass SE_FILE_OBJECT I don't know wheter the function wants the String "SE_FILE_OBJECT" or wheter this is just a constant for a numeric value to pass...

If anyone could give me a hint on how to approach these things I'd be grateful

Cheers

tannerli

Share this post


Link to post
Share on other sites



Hi,

an example how to get the return of the call.

The * after the ptr is described in the help of dllcall()

#include <Array.au3>
$dll=dllopen("advapi32.dll")

local $ppsidOwner,$ppsidGroup,$ppDacl,$ppSacl, $ppSecurityDescriptor

local $ObjectType=1  ;file  http://msdn.microsoft.com/en-us/library/aa379593(v=VS.85).aspx
local $pObjectName="c:\windows\explorer.exe"
local $SecurityInfo=1   ;http://msdn.microsoft.com/en-us/library/cc230369(PROT.10).aspx

if fileexists($pObjectName) then
$erg=dllcall($dll,"int","GetNamedSecurityInfo","str",$pObjectName,"int",$ObjectType,"dword",$SecurityInfo, _
                    "ptr*", $ppsidOwner, _
                    "ptr*", $ppsidGroup, _
                    "ptr*", $ppDacl, _
                    "ptr*", $ppSacl, _
                    "ptr*", $ppSecurityDescriptor)

_arraydisplay($erg)
endif

Share this post


Link to post
Share on other sites

Perfect, this helps a lot.

So the ObjectType would just be the index of the enumeration (I have already seen the mentioned msdn article before, but could not figure out what to pass)

So f.e. if I want to have the Dacl, I just create an appropriate struc using DllStructCreate() pass the pointer to the function using DllStructGetPtr() and then can access the result with DllStructGetData()

Thank you for the informative reply

Cheers

tannerli

Share this post


Link to post
Share on other sites

As i now see... easier said than done...

I've extended your code this far:

#include <Array.au3>
$dll=dllopen("advapi32.dll")

local $ppsidOwner,$ppsidGroup,$ppDacl,$ppSacl, $ppSecurityDescriptor

local $ObjectType=1  ;file  http://msdn.microsoft.com/en-us/library/aa379593(v=VS.85).aspx
local $pObjectName="c:\windows\explorer.exe"
local $SecurityInfo=6 ;http://msdn.microsoft.com/en-us/library/cc230369(PROT.10).aspx

;~ typedef struct _ACL {
;~   BYTE AclRevision;
;~   BYTE Sbz1;
;~   WORD AclSize;
;~   WORD AceCount;
;~   WORD Sbz2;
;~ } ACL, *PACL;

$ppDacl = DllStructCreate("BYTE AclRevision;Byte Sbz1;WORD AclSize;WORD AceCount;WORD Sbz2;")

if fileexists($pObjectName) then
$erg=dllcall($dll,"int","GetNamedSecurityInfo","str",$pObjectName,"int",$ObjectType,"dword",$SecurityInfo, _
                    "ptr*", $ppsidOwner, _
                    "ptr*", $ppsidGroup, _
                    "ptr*", DllStructGetPtr($ppDacl), _
                    "ptr*", $ppSacl, _
                    "ptr*", $ppSecurityDescriptor)

_arraydisplay($erg)
endif

$var = DllStructGetData($ppDacl, "AceCount")
ConsoleWrite($var & @CRLF)

Mainly I have changed the $SecurityInfo that I receive the DACL info and created a struct to store the return value.

But however I change it, I do not seem to get any valid output, every single structmember is set to 0

What am I missing?

Share this post


Link to post
Share on other sites

Global Const $_ACCESS_ALLOWED_ACE = _
    "byte;" & _ ; AceType
    "byte;" & _ ; AceFlags
    "word;" & _ ; AceSize
    "uint;" & _ ; ACCESS_MASK
    "uint;"     ; SidStart

$dll=dllopen("advapi32.dll")

local $ppsidOwner,$ppsidGroup,$ppDacl,$ppSacl, $ppSecurityDescriptor

local $ObjectType=1  ;file  http://msdn.microsoft.com/en-us/library/aa379593(v=VS.85).aspx
local $pObjectName="c:\windows\explorer.exe"
local $SecurityInfo=6 ;http://msdn.microsoft.com/en-us/library/cc230369(PROT.10).aspx

;~ typedef struct _ACL {
;~   BYTE AclRevision;
;~   BYTE Sbz1;
;~   WORD AclSize;
;~   WORD AceCount;
;~   WORD Sbz2;
;~ } ACL, *PACL;

If fileexists($pObjectName) Then

    $erg=dllcall($dll,"int","GetNamedSecurityInfo","str",$pObjectName,"int",$ObjectType,"dword",$SecurityInfo, _
                    "ptr*", 0, _
                    "ptr*", 0, _
                    "ptr*", 0, _ ; ppDacl
                    "ptr*", 0, _
                    "ptr*", 0)
EndIf

If @error = 0 And $erg[0] = 0 Then
    $tACL = DllStructCreate("byte AclRevision;byte Sbz1;word AclSize;word AceCount;word Sbz2;", $erg[6])
    $iSize = DllStructGetData($tACL, "AclSize") - DllStructGetSize($tACL)
    $tACEs = DllStructCreate("byte ACE[" & $iSize & "];", $erg[6]+DllStructGetSize($tACL))

    ConsoleWrite(DllStructGetData($tACEs, "ACE") & @CRLF)
EndIf

Note that it's specified somewhere in the See also links that an application should not directly access the ACE structures members.

Share this post


Link to post
Share on other sites

Thanks authenticity

I see now what I made wrong in my code...

Maybe I should roll up my idea from the beginning:

I wanted to read the ACE's, use LookupAccountSID() to resolve it to a useful name and then use the Active Directory to Display the groups members.

I need to make a documentation over the permissions on a complex folder structure in my company, and since I'm too lazy to do this manuall, I'd rather take the challenging approach

But it looks like it is a bit too advance for my skills, as I am just a humble admin, not really a programmer. I am stuck now anyway since I expected the DACL to contain a list of SID's...

However, thanks for your help, I learned a lot

Share this post


Link to post
Share on other sites

#Include <Memory.au3>

Global Const $_ACCESS_ALLOWED_ACE = _
    "byte AceType;" & _
    "byte AceFlags;" & _
    "word AceSize;" & _
    "uint Mask;" & _
    "uint SidStart;"

$dll=dllopen("advapi32.dll")

local $ppsidOwner,$ppsidGroup,$ppDacl,$ppSacl, $ppSecurityDescriptor

local $ObjectType=1  ;file  http://msdn.microsoft.com/en-us/library/aa379593(v=VS.85).aspx
local $pObjectName="c:\windows\explorer.exe"
local $SecurityInfo=6 ;http://msdn.microsoft.com/en-us/library/cc230369(PROT.10).aspx

;~ typedef struct _ACL {
;~   BYTE AclRevision;
;~   BYTE Sbz1;
;~   WORD AclSize;
;~   WORD AceCount;
;~   WORD Sbz2;
;~ } ACL, *PACL;

If fileexists($pObjectName) Then

    $erg=dllcall($dll,"int","GetNamedSecurityInfo","str",$pObjectName,"int",$ObjectType,"dword",$SecurityInfo, _
                    "ptr*", 0, _
                    "ptr*", 0, _
                    "ptr*", 0, _ ; ppDacl
                    "ptr*", 0, _
                    "ptr*", 0)
EndIf

If @error = 0 And $erg[0] = 0 Then
    $tACL = DllStructCreate("byte AclRevision;byte Sbz1;word AclSize;word AceCount;word Sbz2;", $erg[6])
    $iSize = DllStructGetData($tACL, "AclSize") - DllStructGetSize($tACL)
    $tACEs = DllStructCreate("byte ACE[" & $iSize & "];", $erg[6]+DllStructGetSize($tACL))

    $pOffset = DllStructGetPtr($tACEs)
    $pStartofACEs = DllStructGetPtr($tACEs)

    Do
        $tACE = DllStructCreate($_ACCESS_ALLOWED_ACE, $pOffset)
        $sStringSid = _WinAPI_ConvertSidToStringSid(DllStructGetPtr($tACE, "SidStart"))
        ConsoleWrite($sStringSid & @CRLF)

        $pOffset += DllStructGetData($tACE, "AceSize")
    Until ($pOffset - $pStartofACEs) >= $iSize
EndIf

Func _WinAPI_ConvertSidToStringSid($pSid)
    Local $aResult, $tStringSid, $sStringSid, $hMemory

    $aResult = DllCall("Advapi32.dll", "bool", "ConvertSidToStringSidW", "ptr", $pSid, "ptr*", 0)

    If @error Then Return SetError(@error, @extended, 0)
    If $aResult[0] Then
        $hMemory = $aResult[2]
        $tStringSid = DllStructCreate("wchar[" & _MemGlobalSize($hMemory) & "]", $hMemory)
        $sStringSid = DllStructGetData($tStringSid, 1)
        _MemGlobalFree($hMemory)
        Return SetError(0, 0, $sStringSid)
    EndIf

    Return SetError(_WinAPI_GetLastError(), 0, "")
EndFunc

I really don't know if the SID's are correct. If you're an obedient API user you should call GetACE function instead of directly accessing the ACE structures members.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Great, thanks a lot, these SID's look very authentic to me...

I feel rather guilty for letting you do all the work here... therefore I will work now with this code you provided and try to figure out the rest myself and only ask for your help if I'm really stuck.

And of course i will keep you posted on the endresult, once it can be used for anything.

Thanks again

Edited by tannerli

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Hey guys,

As promised, here the results of your and my combined efforts :blink:

As written in the remarks below, I still need to process the collected data to some useful output format, but I'm not sure how I want it yet. (And it isn't really relevant to the topic as anyone can write an _ExportToCSV() or something similar)

I'm open to any comments, hints and improvement suggestions

;======================================================================================
; _PermissionReport($sRootDir, $fFileType = 1, $iMaxDepth = 0, $sFilter = "")
;Collect Permission Information on a folder
;
;Parameters:
;   string  $sRootDir       The starting directory
;   flag    $fFileType      Flag wheter to collect info on files or folders, this can
;                           be a combination of:
;                               1 = Folders
;                               2 = Files
;   int     $iMaxDepth      Specifies how many levels of subfolders will be reported,
;                           use -1 for no limit (effective limit would be 127 due to
;                           AutoIt recursion limit)
;   string $sFilter         Report only ACE's starting with $sFilter
;
;Return Value:
;   Success:
;   Returns 0
;
;   Failure:
;   Returns -1
;
;Remarks:
;   The function only collects the info, output is yet to be done. (I used my own log
;   function for this example) -> Modify to your needs where slog() is called.
;
;Author:    Marco Tanner
;======================================================================================
#include <Security.au3>

Global Const $_READ =       1179785
Global Const $_EXEC =       1179808
Global Const $_READEXEC =   1179817
Global Const $_WRITE =      1179926
Global Const $_MODIFY =     1245631
Global Const $_FULL =       2032127
Global Const $_ACCESS_ALLOWED_ACE = _
            "byte AceType;" & _
            "byte AceFlags;" & _
            "word AceSize;" & _
            "uint Mask;" & _
            "uint SidStart;"

Func _PermissionReport($sRootDir, $fFileType = 1, $iMaxDepth = 1, $sFilter = "")
    $hSearch = FileFindFirstFile($sRootDir & "\*.*")
    If @error Then Return -1

    While 1
        $sFile = FileFindNextFile($hSearch)
        If @error Then ExitLoop

        If StringInStr(FileGetAttrib($sRootDir & "\" & $sFile), "D") Then
            If BitAND($fFileType, 1) Then _ReadACL($sRootDir & "\" & $sFile, $sFilter)
            If $iMaxDepth <> 0 Then _PermissionReport($sRootDir & "\" & $sFile, $fFileType, $iMaxDepth - 1, $sFilter)
        Else
            If BitAND($fFileType, 2) Then _ReadACL($sRootDir & "\" & $sFile, $sFilter)
        EndIf
    WEnd

    Return 0
EndFunc

Func _ReadACL($sFile, $sFilter)
    Local $ObjectType = 1  ;file  http://msdn.microsoft.com/en-us/library/aa379593(v=VS.85).aspx
    Local $SecurityInfo = 6 ;http://msdn.microsoft.com/en-us/library/cc230369(PROT.10).aspx

    slog(0, $sFile)

    If FileExists($sFile) Then
        $erg=DllCall("Advapi32.dll", "int", "GetNamedSecurityInfo", "str", $sFile, "int", $ObjectType, "dword", $SecurityInfo, _
                        "ptr*", 0, _
                        "ptr*", 0, _
                        "ptr*", 0, _ ; ppDacl
                        "ptr*", 0, _
                        "ptr*", 0)
    Else
        Return -1
    EndIf

    If @error = 0 And $erg[0] = 0 Then

        $tACL = DllStructCreate("byte AclRevision;byte Sbz1;word AclSize;word AceCount;word Sbz2;", $erg[6])
        $iSize = DllStructGetData($tACL, "AclSize") - DllStructGetSize($tACL)
        $tACEs = DllStructCreate("byte ACE[" & $iSize & "];", $erg[6]+DllStructGetSize($tACL))
        $pOffset = DllStructGetPtr($tACEs)
        $pStartofACEs = DllStructGetPtr($tACEs)

        Do
            $tACE = DllStructCreate($_ACCESS_ALLOWED_ACE, $pOffset)
            $bSid = DllStructGetPtr($tACE, "SidStart")
            $aAcct = _Security__LookupAccountSid($bSid)

            $iAccessMask = DllStructGetData($tACE, "Mask")

            If $sFilter <> "" Then
                If(StringLeft($aAcct[0], StringLen($sFilter)) = $sFilter) Then
                    slog(0, StringFormat("%-25s  %s  %s", $aAcct[0], _AccessMaskToString($iAccessMask)))
                EndIf
            EndIf
            $pOffset += DllStructGetData($tACE, "AceSize")
        Until ($pOffset - $pStartofACEs) >= $iSize
    EndIf
EndFunc

Func _AccessMaskToString($iAccessMask)
    Switch $iAccessMask
        Case $_READ
            Return "Read"
        Case $_WRITE
            Return "Write"
        Case $_MODIFY
            Return "Modify"
        Case $_READEXEC
            Return "Read&Exec"
        Case $_FULL
            Return "FullAccess"
    EndSwitch
EndFunc

Func slog($lvl, $msg)
;~  Select
;~      Case $lvl = 0
;~          If $LOGLVL < 3 Then Return
;~      Case $lvl = 1
;~          If $LOGLVL < 2 Then Return
;~      Case $lvl = 2
;~          If $LOGLVL < 1 Then Return
;~  EndSelect

;~  If @Compiled = 1 Then
;~      FileWriteLine($LOG, $msg)
;~  Else
        ConsoleWrite($msg & @CRLF)
;~  EndIf
EndFunc

Func die($msg)
    slog(2,"FATAL:" & $msg & @CRLF & "@Error: " & @error)
    Exit
EndFunc

So long, and thanks for all the fish

tannerli

Edited by tannerli

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0