Subject:
[ruby-ffi] Correct usage of AdjustTokenPrivileges with FFI
From:
Marc Ruehlaender
Date:
9/12/13 2:53 AM
To:
ruby-ffi@googlegroups.com

Hi,

I'm new to Ruby and I'm trying to do some GUI-based test automation of a Win32 application using ruby/rspec and ffi.
(ruby 2.0.0p247 (2013-06-27) [i386-mingw32], ffi 1.9.0)

What I am trying to do is click a toolbar button. (More of an exercise than a necessity, since I could of course call the corresponding menu function.)
To get the coordinates for the mouse click I want to send the TB_GETRECT message to the toolbar of my application.
The second parameter of the message takes a pointer which will take a RECT with the bounding rectangle of the button.
Since I need to allocate memory for this pointer to point to in the applications address space, I want to get DEBUG privileges.

And this is where I am getting stumped.

Relevant code patches:

---------------
#file myapp-test.rb
require './ffi_winapi'

module MyApp

  #start my app
  system 'start "" "<absolute path to my app>"'

  #get the handle for the main window
  sleep 0.2 while (handle = Win.find_window( nil, '<Window title>') ) <= 0
 
  #get the handle for the tool bar
  tool_bar = Win.find_window_ex(handle, 0, "ToolbarWindow32", nil)

  #get the process ID for the process in which tool bar is running
  ppid = FFI::MemoryPointer.new(:uint32, 1)
  tid = Win.get_window_thread_process_id(tool_bar, ppid)
  pid = ppid.read_uint32

  #open the process for getting a security token 
  proc = WinKernel.open_process(WinKernel::PROCESS_QUERY_INFORMATION, false, pid)

  #get a token handle to adjust privileges
  ptoken = FFI::MemoryPointer.new(:long)
  bret = WinAuth.open_process_token(proc, WinAuth::TOKEN_QUERY | WinAuth::TOKEN_ADJUST_DEFAULT, ptoken)
  token = ptoken.read_long

  #intitalize LUID struct
  myluid = WinAuth::Luid.new
  myluid[:lo] = 0
  myluid[:hi] = 0

  #get the system LUID for debug privileges
  WinAuth.lookup_privilege_value("", WinAuth::SE_DEBUG_NAME, myluid)
 
  #up to this point everything seems to be working fine judging by puts debugging

  #prepare the TOKEN_PRIVILEGES struct for adjust token privileges
  mytokenprivs = WinAuth::TokenPrivileges.new(FFI::MemoryPointer.new(WinAuth::TokenPrivileges.size_with_privileges(1)))
  mytokenprivs[:count] = 1
  myluidattr = mytokenprivs.privilege(0)
  myluidattr[:luid] = myluid
  myluidattr[:attributes] = WinAuth::SE_PRIVILEGE_ENABLED

  #code shamelessly adapted from chef code
  plen = FFI::MemoryPointer.new(:long).write_long(mytokenprivs.size_with_privileges)
  prevtokenprivs = WinAuth::TokenPrivileges.new(FFI::MemoryPointer.new(plen.read_long))

  # !!! Failing code !!!
  bret = WinAuth.adjust_token_privileges(token, false, mytokenprivs, mytokenprivs.size_with_privileges, prevtokenprivs, plen)
  err = WinKernel.get_last_error
  puts "Adjust token privileges returned #{bret}; last error: #{err}"
  puts "#{prevtokenprivs[:count]} privileges were modified."


  #clean up
  WinKernel.close_handle(token)
  WinKernel.close_handle(proc)
end
#end file myapp_test.rb
---------------
#excerpts from file ffi_winapi.rb
require 'ffi'

module Win
  extend FFI::Library

  ffi_lib 'user32'
  ffi_convention :stdcall

  #... (consts, structs and method wrappers for user32)

end

module WinKernel
  extend FFI::Library

  ffi_lib 'kernel32'

  #... (consts, structs and method wrappers for kernel32)

end

module WinAuth
  extend FFI::Library

  ffi_lib 'advapi32'
 
  TOKEN_QUERY = 0x0008
  TOKEN_ADJUST_DEFAULT = 0x0080
 
  # BOOL WINAPI OpenProcessToken(_In_ HANDLE ProcessHandle, _In_ DWORD DesiredAccess, _Out_ PHANDLE TokenHandle);
  attach_function :open_process_token, :OpenProcessToken,
                  [ :long, :int, :pointer ], :bool

  class Luid < FFI::Struct
    layout :lo, :int,
           :hi, :int
  end
 
  SE_DEBUG_NAME = "SeDebugPrivilege"
 
  # BOOL WINAPI LookupPrivilegeValue(_In_opt_ LPCTSTR lpSystemName, _In_ LPCTSTR lpName, _Out_ PLUID lpLuid);
  attach_function :lookup_privilege_value, :LookupPrivilegeValueA,
                  [ :string, :string, :pointer], :bool

  class LuidAndAttributes < FFI::Struct
    layout :luid, Luid,
           :attributes, :int
  end
 
  SE_PRIVILEGE_ENABLED = 2
 
  #class definition shamelessly adapted from chef code
  class TokenPrivileges < FFI::Struct
    layout :count, :uint32,
           :privileges, LuidAndAttributes
 
    def self.size_with_privileges(num_privileges)
      offset_of(:privileges) + LuidAndAttributes.size*num_privileges
    end
   
    def size_with_privileges
      TokenPrivileges.size_with_privileges(self[:count])
    end

    def privilege(index)
      LuidAndAttributes.new(pointer + offset_of(:privileges) + (index * LuidAndAttributes.size))
    end
  end

  # BOOL WINAPI AdjustTokenPrivileges(_In_ HANDLE TokenHandle, _In_ BOOL DisableAllPrivileges, _In_opt_ PTOKEN_PRIVILEGES NewState, _In_ DWORD BufferLength, _Out_opt_ PTOKEN_PRIVILEGES PreviousState, _Out_opt_ PDWORD ReturnLength);
  attach_function :adjust_token_privileges, :AdjustTokenPrivileges,
                  [ :long, :bool, :pointer, :int, :pointer, :pointer ], :bool
end

#end file ffi_winapi.rb
---------------

When running the ruby code, I get

Adjust token privileges returned false; last error: 0
0 privileges were modified.

Running the equivalent algorithm implemented in visual C++ works fine (i.e. it declares that 1 privilege has been modified, and also the following steps - not shown in the ruby code - lead to a successful read of the RECT.)
Therefore I assume, the error is in my lack of understanding ffi and/or basic ruby concepts.

Any pointers on how to proceed are appreciated.

Cheers,
Marc

 

--
 
---
You received this message because you are subscribed to the Google Groups "ruby-ffi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ruby-ffi+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.