Driver development using PureBasic

Developed or developing a new product in PureBasic? Tell the world about it.
User avatar
DoubleDutch
Addict
Addict
Posts: 3219
Joined: Thu Aug 07, 2003 7:01 pm
Location: United Kingdom
Contact:

Re: Driver development using PureBasic

Post by DoubleDutch »

This is great - it should be added to the main program. :)
https://deluxepixel.com <- My Business website
https://reportcomplete.com <- School end of term reports system
marroh
User
User
Posts: 72
Joined: Wed Aug 06, 2008 8:21 am

Re: Driver development using PureBasic

Post by marroh »

DoubleDutch wrote:This is great - it should be added to the main program. :)
+1
PureBASIC v5.41 LTS , Windows v8.1 x64
Forget UNICODE - Keep it BASIC !
User avatar
tj1010
Enthusiast
Enthusiast
Posts: 624
Joined: Mon Feb 25, 2013 5:51 pm
Location: US or Estonia
Contact:

Re: Driver development using PureBasic

Post by tj1010 »

Nituvious wrote:Wow, very cool! I thought driver creation was assumed to be impossible with PureBasic?
PB generates FASM, and uses FASM.EXE to build PE/EXE/DLL. This just uses custom macros and intercepts IDE. I guess nobody ever actually looked to see how PB worked.

The problem with ring0 development is it's almost entirely reverse engineering, there is no documentation even on "documented" structures and calls, even if you use WDK. Debugging and analyzing drivers is also an art even for seasoned people; it's all about structures and timing and allocation. Most people I've seen who work with them still don't know how they really work. Using unsupported tools to develop kernel code should be interesting...
The truth hurts.
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Driver development using PureBasic

Post by User_Russian »

The new version, add-ons for PB. :) :)
Unlike the previous version, this version supports string, as well as dynamic and associative arrays, linked lists, and of course the dynamic content in the structures (strings, arrays, lists, etc.). Download. http://pure-basic.narod.ru/forum_files/ ... k_v2.2.zip

Installation.
1. Install PureBasic 5.11 x86 to any folder.
2. Open directory where you installed PureBasic, and in the folder "Compilers" rename files Fasm.exe and Polink.exe in Fasm_.exe and Polink_.exe.
3. Open folder "PureLibraries\Windows\Libraries\" and delete all files.
4. Extract the archive in directory where you installed PureBasic 5.11 x86.
5. Run the program "IDE PB5.11 x86 Patch.exe", which will change the extension saved executable files with .exe on .sys.
Examples in the folder "Examples\Driver\".

Just keep in mind are using the kernel memory. You must use the least possible amount of memory, because it is not enough. There is another feature memory (quote from wasm.ru).
System pool (to user pool have no relation) are two so-called memory pools, which, naturally, are located in the system address space: Pool nonpaged memory (Nonpaged Pool). So named because its pages are never reset the paging file, and therefore never spooled back. Ie the pool is always present in physical memory and is available at any IRQL. One reason for its existence is that the recourse to such memory can cause an error page (Page Fault). These errors lead to the collapse of the system, if there are at IRQL> = DISPATCH_LEVEL. Pool paged memory (Paged Pool). So named because its pages can be reset to the paging file, and therefore need to be pumped up back at the subsequent appeal to them. This memory can be used only when the IRQL is strictly less than DISPATCH_LEVEL. Both pools located in system address space, and hence accessible from any process context. To allocate memory in the system pools, there is a set of functions ExAllocatePoolXxx, and for the return of the allocated memory is only one - ExFreePool.
To select the type of memory (Paged or NonPaged) intended a macro.

Code: Select all

SetPoolMode(Mode)
Current memory type can be determined using a macro.

Code: Select all

GetPoolMode()
Valid values.

Code: Select all

Enumeration
  #Pool_NonPaged ; Only use NonPaged memory. Valid at any level IRQL, but this memory is extremely deficient and it can not be wasted. This is the default.
  #Pool_Paged ; Use only Memory is Paged. Valid at IRQL < #DISPATCH_LEVEL.
  #Pool_Auto ; Automatic selection of the type of memory depending on the IRQL.
EndEnumeration
Changing the type of memory is only valid for the next allocation, and the type is already allocated memory is not changed. And moreover, it acts only on functions PB. On calling the kernel function ExAllocatePool() and the like, are not counted. Example of use in the "Examples\Driver\Simple\SelectMemoryType.pb".
As well need to monitor the the release of memory. Even if the driver has been unloaded from memory, it does not free up resources and memory will be occupied until the system reboots. If memory is NonPaged, this is equivalent to reducing the size of physical memory!
At the end of the procedure DriverUnload() you need to add a line.

Code: Select all

!CALL _PB_EOP
This will release the memory used by the PB-runtime.

A few examples from folder "Examples\Driver\Simple".

String and Random().

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  s.s="1234 "
  s+"5678 "+Random(1234)
  DbgPrint(s)
  
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
Array.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  Dim x.a(10)
  x(10)=2
  ReDim x(200)
  x(200)=4
  s.s=Str(x(10))+" "+x(200)
  DbgPrint(s)
  DbgPrint(Str(ArraySize(x())))
  
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
LinkedList.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  NewList x()
  
  For i=1 To 100
    If AddElement(x())
      x()=i
    EndIf
  Next i
  
  DbgPrint("Size list "+ListSize(x())+" items")
  ForEach x()
    DbgPrint(Str(x()))
  Next
  
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
OSVersion.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"

EnableExplicit


Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
    
  DbgPrint("Unload Driver")
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure

Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected i, String.s="Installed on your computer OS "
    
  DbgPrint("Load Driver")
  
  Select OSVersion()
      Case #PB_OS_Windows_2000
        String+"Windows 2000"
      Case #PB_OS_Windows_XP
        String+"Windows XP"
      Case #PB_OS_Windows_Server_2003
        String+"Windows 2003"
      Case #PB_OS_Windows_Vista
        String+"Windows Vista"
      Case #PB_OS_Windows_Server_2008
        String+"Windows 2008"
      Case #PB_OS_Windows_7
        String+"Windows 7"
      Case #PB_OS_Windows_Server_2008_R2
        String+"Windows 2008"
      Case #PB_OS_Windows_8
        String+"Windows 8"
      Default
        String+"unknown"
  EndSelect
  
  DbgPrint(String)
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
SortArray.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  Dim a.s(4)
  a(0)="1234"
  a(1)="asd"
  a(2)="myt"
  a(3)="zer"
  a(4)="89"
  
  RandomizeArray(a()) ; Рассортировка.
  
  For i=0 To 4
    DbgPrint(a(i))
  Next
  
  DbgPrint("-------------")
  
  SortArray(a(), #PB_Sort_Ascending) ; Сортировка.
  
  For i=0 To 4
    DbgPrint(a(i))
  Next
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
ElapsedMilliseconds.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  DbgPrint("Wait 1 sec.")
  Time = ElapsedMilliseconds()
  Delay(1000)
  DbgPrint(Str(ElapsedMilliseconds()-Time))
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
Memory.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  *Mem.Long = AllocateMemory(20)
  If *Mem
    
    DbgPrint("Memory size: "+Str(MemorySize(*Mem)))
    
    *Mem\l = 1234
    
    *Mem_2.Long = AllocateMemory(20)
    If *Mem_2
      DbgPrint("CopyMemory")
      CopyMemory(*Mem, *Mem_2, MemorySize(*Mem_2))
      DbgPrint("Value: "+Str(*Mem_2\l))
      FreeMemory(*Mem_2)
      *Mem_2=0
    EndIf
    
    DbgPrint("ReAllocateMemory")
    *Mem=ReAllocateMemory(*Mem, 100)
    If *Mem
      DbgPrint("Value: "+Str(*Mem\l))
    EndIf
    
    If *Mem
      FreeMemory(*Mem)
    EndIf
  EndIf
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
AES.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
    ; Should be compiled in ascii mode
  ;
  String$ = "Hello this is a test for AES"
  
  *CipheredString   = AllocateMemory(Len(String$)+1) ; Space for the string and its
  *DecipheredString = AllocateMemory(Len(String$)+1) ; null terminating character (ASCII mode)
  
  If AESEncoder(@String$, *CipheredString, Len(String$), ?Key, 128, ?InitializationVector)
    DbgPrint("Ciphered: "+PeekS(*CipheredString))
    
    AESDecoder(*CipheredString, *DecipheredString, Len(String$), ?Key, 128, ?InitializationVector)
    DbgPrint("Deciphered: "+PeekS(*DecipheredString))
  EndIf
 
  DataSection
    Key:
      Data.b $06, $a9, $21, $40, $36, $b8, $a1, $5b, $51, $2e, $03, $d5, $34, $12, $00, $06
  
    InitializationVector:
      Data.b $3d, $af, $ba, $42, $9d, $9e, $b4, $30, $b4, $22, $da, $80, $2c, $9f, $ac, $41
  EndDataSection
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
Select Memory Type.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
 
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure
 
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  
  ; Этот выбор типа памяти работает только для функций PB. На функции ядра, типа ExAllocatePool(), он не распространяется.
  
  SetPoolMode(#Pool_NonPaged) ; В дальнейшем память будет выделяться только из НЕподкачиваемого пула.
                             ; Это необходимо только для уровня IRQL >= #DISPATCH_LEVEL.
  
  x.s="This NonPagedPool memory"  ; Память под массив выделена из НЕподкачиваемого пула.
  DbgPrint(x)
  
  SetPoolMode(#Pool_Paged)    ; В дальнейшем память будет выделяться только из подкачиваемого пула.
                             ; Будет работать если уровнь IRQL < #DISPATCH_LEVEL, на более высоком уровне может быть BSoD.
  
  y.s="This PagedPool memory"  ; Память под массив выделена из подкачиваемого пула.
  DbgPrint(y)
  
  SetPoolMode(#Pool_Auto)    ; В дальнейшем , будет автоматический выбор типа памяти в зависимости от IRQL..
  
  a.s="Auto mode type memory"  ; В зависимости от уровня IRQL, память будет выделена из подкачиваемого или НЕподкачиваемого пула.
  DbgPrint(a)
  
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
Mutex. Slightly reworked example from help.

Code: Select all

Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
 
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"

EnableExplicit

Global Mutex, ExitFlag

Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
  
  ExitFlag=#True
  Delay(400)
  
  If Mutex
    FreeMutex(Mutex)
  EndIf
  
  DbgPrint("Unload Driver")
  !CALL _PB_EOP ; Освобождение ресурсов.
  
EndProcedure

Procedure WithoutMutex(x)
  Protected a, b
  
  For a = 1 To 5      
    LockMutex(Mutex)
    
    DbgPrint("Thread "+Str(x)+": Trying to print 5x in a row:")
    For b = 1 To 5
      Delay(50)
      
      If ExitFlag=#True
        UnlockMutex(Mutex)
        Break 2
      EndIf
      
      DbgPrint("Thread "+Str(x)+" Line "+Str(b))
    Next b          
    
    UnlockMutex(Mutex)
  Next a   
  
  LockMutex(Mutex)
  DbgPrint("Exit Thread "+x)
  UnlockMutex(Mutex)
  
  PsTerminateSystemThread(#STATUS_SUCCESS)
EndProcedure

Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected i
  
  SetPoolMode(#Pool_Auto)    ; Автоматический выбор типа памяти в зависимости от IRQL.
  
  DbgPrint("Load Driver")
  
  ExitFlag = #False
  
  Mutex = CreateMutex()
  
  If Mutex
    
    LockMutex(Mutex)
    DbgPrint("Run ThreadID "+Str(CreateThread(@WithoutMutex(), 1)))
    Delay(25)
    DbgPrint("Run ThreadID "+Str(CreateThread(@WithoutMutex(), 2)))
    Delay(25)
    DbgPrint("Run ThreadID "+Str(CreateThread(@WithoutMutex(), 3)))
    UnlockMutex(Mutex)
    
  Else
    DbgPrint("Error CreateMutex()")
  EndIf
    
  *DriverObject\DriverUnload = @DriverUnload()
  ProcedureReturn #STATUS_SUCCESS
EndProcedure
To test the drivers, use program "KmdManager" and Dbgview. The program "KmdManager" for run driver. Necessary specify the path to the driver file and consistent, click on the button "Register", "Run", "Stop" and "Unregister".
The program "Dbgview" is a debugger that displays messages sent function DbgPrint(). Necessary make sure as in menu "Capture", is checked "Capture Kernel". This item need to checkmark if there is no check mark .

This is what displays the program Dbgview when run, the sample "AES".

Image

Version History.

2.2 - Supports function OSVersion(), Mutex-functions, as well as function CreateThread() and WaitThread(), from library "Thread".

****

2.1 - The default is used nonpaged memory, that is needed to initialize the runtime PB.

****

2.0 - Supported library: "Array", "Cipher", "LinkedList", "Map", "Math", "Memory", "Misc", "RegularExpression", "Sort" and "String".

****

1.0 - The first version. Only supports library "Math" and "Memory".
Test drivers must be in a virtual machine.
marroh
User
User
Posts: 72
Joined: Wed Aug 06, 2008 8:21 am

Re: Driver development using PureBasic

Post by marroh »

Thank you for the update. :D
PureBASIC v5.41 LTS , Windows v8.1 x64
Forget UNICODE - Keep it BASIC !
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Driver development using PureBasic

Post by User_Russian »

Version for PB 5.31 x64 (for developing x64 driver). http://pure-basic.narod.ru/forum_files/ ... Plugin.zip
Installation.
1. Install PureBasic 5.31 x64 to any folder.
2. Open directory where you installed PureBasic, and in the folder "Compilers" rename files Fasm.exe and Polink.exe in Fasm_.exe and Polink_.exe.
3. Open folder "PureLibraries\Windows\Libraries\" and delete all files.
4. Extract the archive in directory where you installed PureBasic 5.31 x64.
5. Run the program "IDE PB5.31 x64 Patch.exe", which will change the extension saved executable files with .exe on .sys.
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: Driver development using PureBasic

Post by Keya »

Amazing! :)
Russian hackers make the world more interesting, where would we be without them!? :D
https://www.youtube.com/user/CrazyRussianHacker
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: Driver development using PureBasic

Post by bbanelli »

@User_Russian

Wow, great!

I might have bothered you before with that question but I really don't remember the answer, so please forgive me if you did tell :D - can drivers created with PB 5.31 (x64) be signed with code signing certificate from Comodo and be used without any issues on Windows without DDISABLE_INTEGRITY_CHECKS and TESTSIGNING ON switch and other necessary adjustments?
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
User_Russian
Addict
Addict
Posts: 1443
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Driver development using PureBasic

Post by User_Russian »

No matter in what IDE driver is compiled (for example VS or PB). For Windows x64, need is valid signature and then drivers will be installed.
User avatar
Rings
Moderator
Moderator
Posts: 1427
Joined: Sat Apr 26, 2003 1:11 am

Re: Driver development using PureBasic

Post by Rings »

download is not working for me
SPAMINATOR NR.1
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: Driver development using PureBasic

Post by c4s »

@Rings
For me neither. Then I tried several proxy servers from USA, Russia, China and Brazil... Interestingly only the latter one seemed to work fine.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
Hi-Toro
Enthusiast
Enthusiast
Posts: 265
Joined: Sat Apr 26, 2003 3:23 pm

Re: Driver development using PureBasic

Post by Hi-Toro »

They do still download if you paste the URLs into the http://archive.org/ Wayback Machine.
James Boyd
http://www.hi-toro.com/
Death to the Pixies!
AAT
Enthusiast
Enthusiast
Posts: 256
Joined: Sun Jun 15, 2008 3:13 am
Location: Russia

Re: Driver development using PureBasic

Post by AAT »

Rings, c4s hi!
i have no problem with download, so i copy this archieve to another place (link will be available for 90 days)
http://rghost.ru/8rhKrDW7V

I do not know why the author did not answer you.

Good luck!
User avatar
Keya
Addict
Addict
Posts: 1891
Joined: Thu Jun 04, 2015 7:10 am

Re: Driver development using PureBasic

Post by Keya »

AAT wrote:I do not know why the author did not answer you.
He is too busy adding proper x64 support, leave him be! :D
Zerosurf
New User
New User
Posts: 3
Joined: Fri Oct 14, 2005 8:18 pm

Re: Driver development using PureBasic

Post by Zerosurf »

Does this mean, it´s possible do code a virtual monitor driver in purebasic now?
Post Reply