C .so library Python - python

Now my code works with a normal c library, but I need to use a .so library from Caen and I get Segmentation fault. This is the code:
from ctypes import *
lib = CDLL('./libcaenhvwrapper.so.5.56')
lib.CAENHVInitSystem.restype = c_int
lib.CAENHVInitSystem.argtypes = [c_int, c_int, c_char_p, c_char_p, c_char_p]
lib.CAENHVGetError.restype = c_int
CAENHV_SYSTEM_TYPE_t = c_int
sy1527 = CAENHV_SYSTEM_TYPE_t(0)
sy2527 = CAENHV_SYSTEM_TYPE_t(1)
sy4527 = CAENHV_SYSTEM_TYPE_t(2)
sy5527 = CAENHV_SYSTEM_TYPE_t(3)
n568 = CAENHV_SYSTEM_TYPE_t(4)
v65xx = CAENHV_SYSTEM_TYPE_t(5)
n1470 = CAENHV_SYSTEM_TYPE_t(6)
v8100 = CAENHV_SYSTEM_TYPE_t(7)
link = c_int
LINKTYPE_TCPIP = link(0)
LINKTYPE_RS232 = link(1)
LINKTYPE_CAENET = link(2)
LINKTYPE_USB = link(3)
LINKTYPE_OPTLINK = link(4)
LINKTYPE_USB_VCP = link(5)
string15=c_char*15
address=string15('1','3','7','.','1','3','8','.','1','3','.','2','0','3','\0')
userName = c_char_p('user')
passwd = c_char_p('user')
ret_init = lib.CAENHVInitSystem(0, 0, address, userName, passwd)
when I try to call the function I get a segmentation fault. I think the types are correctly defined. Below you can see a piece of code which works ok.
from ctypes import *
lib2 = CDLL('/lib64/libc.so.6')
string15=c_char*15
address=string15('1','3','7','.','1','3','8','.','1','3','.','2','0','3','\0')
address1=create_string_buffer('137.138.13.203')
address2=c_char_p('137.138.13.200')
userName = c_char_p('user')
passwd = c_char_p('user')
a= lib2.strncmp(address, userName, c_int(4))
a= lib2.strncmp(userName, address, 4)
a= lib2.strncmp(address2, address, 15)
lib2.printf('%d\n', ret_init)
lib2.printf('%s\n', address)
lib2.printf('%s\n', address1)
lib2.printf('%s\n', address2)
lib2.printf('%d\n', lib2.strlen(address))
lib2.printf('%d\n', lib2.strlen(address1))
lib2.printf('%d\n', lib2.strlen(adrress2))

From a quick search:
CAENHVRESULT CAENHVInitSystem(
const char *SystemName, // In
int LinkType,
void *Arg,
const char *UserName,
const char *Password
);
First parameter id definitively a "pointer to char", you should declare it like that:
lib.CAENHVInitSystem.argtypes = [c_char_p, c_int, c_int, c_char_p, c_char_p, c_char_p]
In addition:
ret_init = lib.CAENHVInitSystem(0, 0, address, userName, passwd)
# ^
You pass NULL as SystemName (as NULL is ((void*)0) on most systems). According to the doc I quickly read, this is not explicitly supported.
This is the first function with parameter SystemName to call, and it must be called for all the HV power supplies the user wants to control

Related

PYthon ctypes 'TypeError' LP_LP_c_long instance instead of _ctypes.PyCPointerType

I try to use a dll which is written in C++. It has this function:
bool PMDllWrapperClass::GetDeviceList(DEVICE** pDeviceArray, int* nDeviceCount, LAN_DEVICE** pLanDeviceArray, int LanDeviceCount, int InterfaceTypeToSearch)
I tried:
cP = ctypes.POINTER(ctypes.POINTER(ctypes.c_int64))
cIP = ctypes.POINTER(ctypes.c_int32)
cLP = ctypes.POINTER(ctypes.c_int32)
cDC = ctypes.c_int32()
cIS = ctypes.c_int32()
resultgetdev = PMDll.GetDeviceList(cP, cIP, cLP, cDC, cIS)
But it says:
ctypes.ArgumentError: argument 1: <class 'TypeError'>: expected LP_LP_c_long instance instead of _ctypes.PyCPointerType
I also tried using a double Pointer, but non worked for it. Can I solve it with ctypes or is that not possible?
The error message is due to passing types instead of instances. You should declare the argument types and return type so ctypes can double-check the values passed are correct.
This needs more information to be accurate, but the minimum you need is:
test.cpp
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
struct DEVICE;
struct LAN_DEVICE;
extern "C" __declspec(dllexport)
bool GetDeviceList(DEVICE** pDeviceArray, int* nDeviceCount, LAN_DEVICE** pLanDeviceArray, int LanDeviceCount, int InterfaceTypeToSearch) {
return true;
}
test.py:
from ctypes import *
class DEVICE(Structure):
_fields_ = () # members??
class LAN_DEVICE(Structure):
_fields_ = () # members??
dll = CDLL('./test')
dll.GetDeviceList.argtypes = POINTER(POINTER(DEVICE)), POINTER(c_int), POINTER(POINTER(LAN_DEVICE)), c_int, c_int
dll.GetDeviceList.restype = c_bool
device_list = POINTER(DEVICE)() # create instances to pass by reference for output(?) parameters
landev_list = POINTER(LAN_DEVICE)()
dev_count = c_int()
lan_count = 5 # ??
search_type = 1 # ??
result = dll.GetDeviceList(byref(device_list),byref(dev_count),byref(landev_list),lan_count,search_type)

SymInitialize python

from ctypes import *
from capstone import *
k32 = windll.kernel32
dbghelp = cdll.LoadLibrary('dbghelp.dll')
handle = k32.LoadLibraryEx(modulePath, 0, 1) #DONT_RESOLVE_DLL_REFERENCES
hproc = k32.GetCurrentProcess()
ret = dbghelp.SymInitialize(hproc, sympath, 1)
SymInitialize returns 0
GetLastError returns -1073741813
What I'm doing wrong, same code written in C++ works just fine.
I specified exact function signature, now it works.
from ctypes.wintypes import HANDLE, LPCSTR, UINT
si = windll.dbghelp.SymInitialize
si.argtypes = [HANDLE, LPCSTR, UINT]

Python ctypes: how to allocate output buffer for C function in callback

I have next callback as one of arguments in function in c-code:
typedef unsigned char* (*my_callback)(int size);
//for example:
unsigned char * tmp_buff = nullptr;
tmp_buff = i_alloc_fn(10);
printf("Tmp buff addr = %d.\n", tmp_buff);
*tmp_buff = 111;
printf("I am still alive");
I am trying to provide this callback from python (C-code is loaded as .so lib). I tried 2 ways.
ALLOC_CALLBACK_FUNC = ctypes.CFUNCTYPE(ctypes.c_char_p, ctypes.c_int)
#...
def py_alloc_callback(size):
libc = ctypes.CDLL("libc.so.6")
mem_ptr = libc.malloc(ctypes.c_uint(size))
return mem_ptr
And
ALLOC_CALLBACK_FUNC = ctypes.CFUNCTYPE(ctypes.c_char_p, ctypes.c_int)
stringbuffer = ''
#...
def py_alloc_callback(size):
global stringbuffer
stringbuffer=ctypes.create_string_buffer(size)
return ctypes.POINTER(ctypes.c_ubyte)(stringbuffer)
But both variants led to segmentation fault in C-code when it tried to write to allocated memory.
Please, help me fix it
mem_ptr = libc.malloc(ctypes.c_uint(size))
is clearly wrong. The parameter to malloc is of type size_t.
Now it works:
def py_alloc_callback(size):
libc = ctypes.CDLL("libc.so.6")
alloc_f = libc.malloc
alloc_f.restype = ctypes.c_void_p
alloc_f.argtypes = [ ctypes.c_uint ]
return alloc_f(ctypes.c_uint(size))

GetTokenInformation with ctypes

I'm trying to use the GetTokenInformation function with ctypes.
The problem is that it will always print None.
import winappdbg
from ctypes import *
LPVOID = c_void_p
PVOID = LPVOID
PSID = PVOID
DWORD = c_uint32
class SID_AND_ATTRIBUTES(Structure):
_fields_ = [
("Sid", PSID),
("Attributes", DWORD),
]
class TOKEN_USER(Structure):
_fields_ = [
("User", SID_AND_ATTRIBUTES),]
tokenprivs = (winappdbg.win32.TOKEN_QUERY | winappdbg.win32.TOKEN_READ | winappdbg.win32.TOKEN_IMPERSONATE | winappdbg.win32.TOKEN_QUERY_SOURCE | winappdbg.win32.TOKEN_DUPLICATE | winappdbg.win32.TOKEN_ASSIGN_PRIMARY)
hProcess = winappdbg.win32.OpenProcess(winappdbg.win32.PROCESS_QUERY_INFORMATION, False, winappdbg.win32.GetCurrentProcessId())
hToken = winappdbg.win32.OpenProcessToken(hProcess, DesiredAccess = tokenprivs)
tokeninformation = TOKEN_USER()
dwLength = DWORD(0)
windll.advapi32.GetTokenInformation(hToken, winappdbg.win32.TokenUser, byref(tokeninformation), sizeof(TOKEN_USER), byref(dwLength))
print tokeninformation.User.Sid
P.S. I'm aware that win32security.GetTokenInformation exists. But I want to use ctypes because of the real process handlers.
EDIT:
Working code:
import winappdbg
from ctypes import *
LPVOID = c_void_p
PVOID = LPVOID
PSID = PVOID
DWORD = c_uint32
class SID_AND_ATTRIBUTES(Structure):
_fields_ = [
("Sid", PSID),
("Attributes", DWORD),
]
class TOKEN_USER(Structure):
_fields_ = [
("User", SID_AND_ATTRIBUTES),]
tokenprivs = (winappdbg.win32.TOKEN_QUERY | winappdbg.win32.TOKEN_READ | winappdbg.win32.TOKEN_IMPERSONATE | winappdbg.win32.TOKEN_QUERY_SOURCE | winappdbg.win32.TOKEN_DUPLICATE | winappdbg.win32.TOKEN_ASSIGN_PRIMARY)
hProcess = winappdbg.win32.OpenProcess(winappdbg.win32.PROCESS_QUERY_INFORMATION, False, winappdbg.win32.GetCurrentProcessId())
hToken = winappdbg.win32.OpenProcessToken(hProcess, DesiredAccess = tokenprivs)
dwSize = DWORD(0)
pStringSid = winappdbg.win32.LPSTR()
windll.advapi32.GetTokenInformation(hToken, winappdbg.win32.TokenUser, None, 0, byref(dwSize))
address = windll.kernel32.LocalAlloc(0x0040, dwSize)
print "Address: " + str(address)
windll.advapi32.GetTokenInformation(hToken, winappdbg.win32.TokenUser, address, dwSize, byref(dwSize))
print FormatError(GetLastError())
pToken_User = cast(address, POINTER(TOKEN_USER))
windll.advapi32.ConvertSidToStringSidA(pToken_User.contents.User.Sid, byref(pStringSid))
print "SID: " + pStringSid.value
Although a query for the token information class TokenUser stores a TOKEN_USER structure in the target buffer, it does not contain all the required information by itself. As you can see in the structure's documentation, it contains just the SID_AND_ATTRIBUTES structure, which in turn contains only a pointer to a SID and an integer with flags.
If you added some more error checking, you would see that your call to GetTokenInformation() does not succeed, the reported error code is ERROR_INSUFFICIENT_BUFFER (122) and dwLength is set to something like 36 (definitely more than sizeof(TOKEN_USER), which is just 8).
Apparently the function wants enough space in the target buffer to store even the SID itself, then point to that extra data from the documented output structure TOKEN_USER.
I don't know Ctypes much, but you will need to create the output buffer as a real buffer/array instead of just the structure, and perform some casting on it to get the data. You can either take the easy way and create the buffer large enough on the first try, or call the function twice, first to get the required buffer length, second to fill it.

Python Ctypes Read/WriteProcessMemory() - Error 5/998 Help!

Please don't get scared but the following code, if you are familiar with ctypes or C it should be easy to read.
I have been trying to get my ReadProcessMemory() and WriteProcessMemory() functions to be working for so long and have tried almost every possibility but the right one.
It launches the target program, returns its PID and handle just fine. But I always get a error code of 5 - ERROR_ACCESS_DENIED. When I run the read function(forget the write for now). I am launching this program as what I believe to be a CHILD process with PROCESS_ALL_ACCESS or CREATE_PRESERVE_CODE_AUTHZ_LEVEL.
I have also tried PROCESS_ALL_ACCESS and PROCESS_VM_READ when I open the handle.
I can also say that it is a valid memory location because I can find it on the running program with CheatEngine.
As for VirtualQuery() I get an error code of 998 - ERROR_NOACCESS which further confirms my suspicion of it being some security/privilege problem.
Any help or ideas would be very appreciated, again, it's my whole program so far, don't let it scare you =P.
from ctypes import *
from ctypes.wintypes import BOOL
import binascii
BYTE = c_ubyte
WORD = c_ushort
DWORD = c_ulong
LPBYTE = POINTER(c_ubyte)
LPTSTR = POINTER(c_char)
HANDLE = c_void_p
PVOID = c_void_p
LPVOID = c_void_p
UNIT_PTR = c_ulong
SIZE_T = c_ulong
class STARTUPINFO(Structure):
_fields_ = [("cb", DWORD),
("lpReserved", LPTSTR),
("lpDesktop", LPTSTR),
("lpTitle", LPTSTR),
("dwX", DWORD),
("dwY", DWORD),
("dwXSize", DWORD),
("dwYSize", DWORD),
("dwXCountChars", DWORD),
("dwYCountChars", DWORD),
("dwFillAttribute",DWORD),
("dwFlags", DWORD),
("wShowWindow", WORD),
("cbReserved2", WORD),
("lpReserved2", LPBYTE),
("hStdInput", HANDLE),
("hStdOutput", HANDLE),
("hStdError", HANDLE),]
class PROCESS_INFORMATION(Structure):
_fields_ = [("hProcess", HANDLE),
("hThread", HANDLE),
("dwProcessId", DWORD),
("dwThreadId", DWORD),]
class MEMORY_BASIC_INFORMATION(Structure):
_fields_ = [("BaseAddress", PVOID),
("AllocationBase", PVOID),
("AllocationProtect", DWORD),
("RegionSize", SIZE_T),
("State", DWORD),
("Protect", DWORD),
("Type", DWORD),]
class SECURITY_ATTRIBUTES(Structure):
_fields_ = [("Length", DWORD),
("SecDescriptor", LPVOID),
("InheritHandle", BOOL)]
class Main():
def __init__(self):
self.h_process = None
self.pid = None
def launch(self, path_to_exe):
CREATE_NEW_CONSOLE = 0x00000010
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000
startupinfo = STARTUPINFO()
process_information = PROCESS_INFORMATION()
security_attributes = SECURITY_ATTRIBUTES()
startupinfo.dwFlags = 0x1
startupinfo.wShowWindow = 0x0
startupinfo.cb = sizeof(startupinfo)
security_attributes.Length = sizeof(security_attributes)
security_attributes.SecDescriptior = None
security_attributes.InheritHandle = True
if windll.kernel32.CreateProcessA(path_to_exe,
None,
byref(security_attributes),
byref(security_attributes),
True,
CREATE_PRESERVE_CODE_AUTHZ_LEVEL,
None,
None,
byref(startupinfo),
byref(process_information)):
self.pid = process_information.dwProcessId
print "Success: CreateProcess - ", path_to_exe
else:
print "Failed: Create Process - Error code: ", windll.kernel32.GetLastError()
def get_handle(self, pid):
PROCESS_ALL_ACCESS = 0x001F0FFF
PROCESS_VM_READ = 0x0010
self.h_process = windll.kernel32.OpenProcess(PROCESS_VM_READ, False, pid)
if self.h_process:
print "Success: Got Handle - PID:", self.pid
else:
print "Failed: Get Handle - Error code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)
def read_memory(self, address):
buffer = c_char_p("The data goes here")
bufferSize = len(buffer.value)
bytesRead = c_ulong(0)
if windll.kernel32.ReadProcessMemory(self.h_process, address, buffer, bufferSize, byref(bytesRead)):
print "Success: Read Memory - ", buffer.value
else:
print "Failed: Read Memory - Error Code: ", windll.kernel32.GetLastError()
windll.kernel32.CloseHandle(self.h_process)
windll.kernel32.SetLastError(10000)
def write_memory(self, address, data):
count = c_ulong(0)
length = len(data)
c_data = c_char_p(data[count.value:])
null = c_int(0)
if not windll.kernel32.WriteProcessMemory(self.h_process, address, c_data, length, byref(count)):
print "Failed: Write Memory - Error Code: ", windll.kernel32.GetLastError()
windll.kernel32.SetLastError(10000)
else:
return False
def virtual_query(self, address):
basic_memory_info = MEMORY_BASIC_INFORMATION()
windll.kernel32.SetLastError(10000)
result = windll.kernel32.VirtualQuery(address, byref(basic_memory_info), byref(basic_memory_info))
if result:
return True
else:
print "Failed: Virtual Query - Error Code: ", windll.kernel32.GetLastError()
main = Main()
address = None
main.launch("C:\Program Files\ProgramFolder\Program.exe")
main.get_handle(main.pid)
#main.write_memory(address, "\x61")
while 1:
print '1 to enter an address'
print '2 to virtual query address'
print '3 to read address'
choice = raw_input('Choice: ')
if choice == '1':
address = raw_input('Enter and address: ')
if choice == '2':
main.virtual_query(address)
if choice == '3':
main.read_memory(address)
Thanks!
You should try to set debugging privileges to your process.
Use the following code once before you try to Open / Create a process.
class TOKEN_PRIVILEGES( Structure ):
_fields_ = [
('PrivilegeCount', c_uint),
('Luid', LUID),
('Attributes', c_uint) ]
OpenProcessToken = windll.advapi32.OpenProcessToken
OpenProcessToken.argtypes = [
c_int, # HANDLE ProcessHandle
c_uint, # DWORD DesiredAccess
c_void_p ] # PHANDLE TokenHandle
OpenProcessToken.restype = ErrorIfZero
AdjustTokenPrivileges = windll.advapi32.AdjustTokenPrivileges
AdjustTokenPrivileges.argtypes = [
c_int, # HANDLE TokenHandle
c_int, # BOOL DisableAllPrivileges
c_void_p, # PTOKEN_PRIVILEGES NewState
c_uint, # DWORD BufferLength
c_void_p, # PTOKEN_PRIVILEGES PreviousState
c_void_p ] # PDWORD ReturnLength
AdjustTokenPrivileges.restype = ErrorIfZero
LookupPrivilegeValue = windll.advapi32.LookupPrivilegeValueA
LookupPrivilegeValue.argtypes = [
c_char_p, # LPCTSTR lpSystemName
c_char_p, # LPCTSTR lpName
c_void_p ] # PLUID lpLuid
LookupPrivilegeValue.restype = ErrorIfZero
access_token = c_int(0)
privileges = TOKEN_PRIVILEGES()
OpenProcessToken( GetCurrentProcess(), win32con.TOKEN_QUERY | win32con.TOKEN_ADJUST_PRIVILEGES, byref(access_token) )
access_token = access_token.value
LookupPrivilegeValue( None, "SeDebugPrivilege", byref(privileges.Luid) )
privileges.PrivilegeCount = 1
privileges.Attributes = 2
AdjustTokenPrivileges(
access_token,
0,
byref(privileges),
0,
None,
None )
CloseHandle( access_token )
Maybe this will help you: Creating a Security Descriptor for a New Object in C++
One possible reason for your access denied error is that the user under which you run WriteProcessMemory runs needs to have DEBUG privilege.
Starting with Vista, this privilege is only activated for Administrators, and only when running the application with "Run as Admin".
You can add the privilege to any account.
I see several problems with your code, and it's difficult to know which one is the underlying cause of your exact problem. For example, the line:
address = raw_input('Enter and address: ')
Should probably be something like:
address = long(raw_input('Enter and address: '), 0)
As the code stands, every time you pass address to a function via ctypes what you are actually doing is creating a temporary buffer which contains exactly the string typed by the user and passing in the address of that buffer in the Python process. Definitely not what you want. If I fix that issue, then your program seems to work most of the time.
From my limited testing, most (all?) of the rest of the failures can be fixed by setting the correct argtypes for ReadProcessMemory. This is the single biggest issue I see with ctypes code, a problem exacerbated by handling ctypes.c_voidp as int in Python. If argtypes is not specified, then all arguments are considered to be ctypes.c_int. Anything outside of the range of signed integer -- a pointer or handle with high bit set, for example -- is silently truncated.
Not the cause of your bugs but suboptimal are the lines:
buffer = c_char_p("The data goes here")
bufferSize = len(buffer.value)
The ctypes module provides functions for creating buffers:
bufferSize = 32
buffer = ctypes.create_string_buffer(bufferSize)
Hopefully this will get you down the right path.
PROCESS_VM_READ is not enough: Try use both PROCESS_VM_WRITE + PROCESS_VM_OPERATION. I also received an error violation but the process memory still changed. Add try catch to keep your program alive.
PROCESS_VM_READ = 0x0010
PROCESS_VM_WRITE = 0x0020
PROCESS_VM_OPERATION = 0x0008
PROCESS_ALL_ACCESS = 0x1F0FFF
For me PROCESS_VM_WRITE was not enough, I needed to add PROCESS_VM_OPERATION as well.

Categories