poniedziałek, 22 lutego 2016

EDKII and QEMU - remote debugging with gdb

While working with UEFI debugger can be very helpful. I was using EDKII project to write my UEFI applications and I was testing it with QEMU. I added my application information file to the OvmfPkg module information and this let me to running my program using existing script.
To build OvmfPkg and run QEMU run (in the OvmfPkg folder):
 ./build.sh -A IA32 qemu -s -monitor stdio -debugcon file:debug.log -global isa-debugcon.iobase=0x402  

After start debug.log file will be created where you can read output from UEFI.
We need to know where your application will be loaded (memory address). Run your application in QEMU:
 Shell> fs0:  
 fs0:\> MyApp.efi  

Open debug.log file (in the EDKII directory), and find line with name of your loaded application. You should get something like this:
 Loading driver at 0x00006B75000 EntryPoint=0x00006B75220 MyApp.efi  

And this is our address:

Now open second terminal, open directory with your application's debugging symbols and efi file (for me: Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.debug) and run gdb:
 gdb --tui  
We need to know where particular sections are located. Load efi file and enter info files:
 (gdb) file MyApp.efi  
 Reading symbols from MyApp.efi...(no debugging symbols found)...done.  
 (gdb) info files  
 Symbols from ".../edk2/Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.efi".  
 Local exec file:  
     `.../Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.efi', file type pei-i386.  
     Entry point: 0x220  
     0x00000220 - 0x00003a40 is .text  
     0x00003a40 - 0x00004320 is .data  
     0x00004320 - 0x00004520 is .reloc  

We need to calculate our addresses for text and data section. Application is loaded under 0x00006B75220 (entry point) and we know text and data offsets.
text = 0x06B75220
data = 0x06B75220 + 0x00003a40 = 0x06B78C60

Now unload efi file:
 (gdb) file  
 No executable file now.  
 No symbol file now.  

Load symbols:
 (gdb) add-symbol-file MyApp.debug 0x06B75220 -s .data 0x06B78C60
add symbol table from file "MyApp.debug" at
        .text_addr = 0x6b75220
        .data_addr = 0x6b78c60
(y or n) y
Reading symbols from MyApp.debug...done.

You can add some breakpoints, for example:
 break UefiMain  

And attach debugger to the QEMU:
 target remote localhost:1234  

And run QEMU:
 ./build.sh -A IA32 qemu -s -monitor stdio -debugcon file:debug.log -global isa-debugcon.iobase=0x402  

Machine will be paused, type "continue", load your application. Done!


Samba 3 with LDAP as a Primary Domain Controller

In this tutorial I will show how to configure samba 3 as a PDC with LDAP support. It will be possible also to use domain users on the server machine. I was using minimal Debian 8, openLDAP 2.4 (from repositories) and samba 3.6 (compiled from sources). My hostname is ldapserv and domain domain.edu


First install LDAP from repository:
 apt-get install slapd ldap-utils  

Then edit /etc/ldap/ldap.conf file and set your domain base and URI:
 BASE   dc=domain,dc=edu  
 URI    ldap://  

You can check if it is working with:
 ldapsearch -x  

You should get information about domain and admin.
Now create temporary file (temp.ldif) with this content:
 dn: ou=People,dc=domena,dc=edu  
 ou: People  
 objectClass: organizationalUnit  
 dn: ou=Group,dc=domena,dc=edu  
 ou: Group  
 objectClass: organizationalUnit  
This describes new nodes in our LDAP tree which will be used for our users and groups.
Add these nodes to the tree:
 ldapadd -c -x -D cn=admin,dc=domain,dc=edu -W -f temp.ldif  
cn=admin,dc=domain,dc=edu this is my LDAP admin

Restart slapd:
 systemctl restart slapd.service  

Now we can create and add new user. Open new temporary file (john.ldif):
 dn: cn=john,ou=group,dc=domain,dc=edu  
 cn: john  
 gidNumber: 20000  
 objectClass: top  
 objectClass: posixGroup  
 dn: uid=john,ou=people,dc=domain,dc=edu  
 uid: john  
 uidNumber: 20000  
 gidNumber: 20000  
 cn: john  
 sn: john  
 objectClass: top  
 objectClass: person  
 objectClass: posixAccount  
 objectClass: shadowAccount  
 loginShell: /bin/bash  
 homeDirectory: /home/john  

Add john.ldif:
 ldapadd -c -x -D cn=admin,dc=domain,dc=edu -W -f john.ldif  

Set the password for john:
 ldappasswd -x -D cn=admin,dc=domain,dc=edu -W -S uid=john,ou=people,dc=domain,dc=edu  


When you enter command "id john", system couldn't find our user. We can make it possible.
 apt-get install libnss-ldap nscd  

Edit /etc/libnss-ldap.conf:
 BASE   dc=domain,dc=edu  
 URI    ldap://  

Edit /etc/nsswitch.conf and change these lines to:
 passwd:     files ldap  
 group:      files ldap  

 systemctl stop nscd.service  

And check again "id john", now you should see information about your user.


In this moment our OS know user "john", but it is impossible to log in. We must provide information about passwords for PAM. Install ldap support:
 apt­-get install libpam­ldap  

Again enter your ldap base and uri in this file:
 nano /etc/pam_ldap.conf  

Then write to files (and delete previous content):
 account sufficient      pam_unix.so  
 account required        pam_ldap.so  

 auth [success=1 default=ignore] pam_unix.so nullok_secure  
 auth required pam_ldap.so use_first_pass  
 auth required pam_permit.so    

 session required        pam_unix.so  
 session required        pam_mkhomedir.so skel=/etc/skel/ umask=0022   

Now test settings (on second terminal, without restarting, because you can lost your system).


We will create domain controller with samba. I will be using Windows 7 clients so samba version mus be >= 3.3.
Download and extract samba sources:
 wget https://download.samba.org/pub/samba/samba­3.6.25.tar.gz  
 tar ­zxvf samba­3.6.25.tar.gz  
 cd samba­3.6.25/source3  

Install required libraries:
 apt­get install gcc make libldap2­dev libkrb5­dev libpam0g­dev  

Configure and compile samba (with LDAP support, install dir: ​/usr/local/samba):
 ./configure ­­prefix=/usr/local/samba/ ­­--with­-ldap ­­--with­-ads ­­--with­-pam ­­--disable­-cups  
 make install    

Add samba schema to the LDAP schema directory:
 cd ..  
 cp examples/LDAP/samba.schema /etc/ldap/schema/samba.schema   

Now we will add this schema to the LDAP configuration. To do this using LDAP 2.4 we must create ldif file. Create file schema_convert.conf:
 cd ~/  
 nano schema_convert.conf  

And pase this content:
 include /etc/ldap/schema/core.schema  
 include /etc/ldap/schema/collective.schema  
 include /etc/ldap/schema/corba.schema  
 include /etc/ldap/schema/cosine.schema  
 include /etc/ldap/schema/duaconf.schema  
 include /etc/ldap/schema/dyngroup.schema  
 include /etc/ldap/schema/inetorgperson.schema  
 include /etc/ldap/schema/java.schema  
 include /etc/ldap/schema/misc.schema  
 include /etc/ldap/schema/nis.schema  
 include /etc/ldap/schema/openldap.schema  
 include /etc/ldap/schema/ppolicy.schema  
 include /etc/ldap/schema/samba.schema    

Generate cn=samba.ldif file using slapcat:
 mkdir ­-p ldif_output  
 slapcat ­-f ~/schema_convert.conf ­-F ~/ldif_output ­-n0 ­-s "cn={12}samba,cn=schema,cn=config"  > ~/cn=samba.ldif  

Edit file:
 nano cn=samba.ldif    

Delete {13} from lines 1 and 3:
 dn: cn=samba,cn=schema,cn=config  
 objectClass: olcSchemaConfig  
 cn: samba    

And delete this lines (from the end of file):
 structuralObjectClass: olcSchemaConfig  
 entryUUID: bd8a7a82­3cb8­102f­8d5f­070b4e5d16f8  
 creatorsName: cn=config  
 createTimestamp: 20100815125953Z   
 entryCSN: 20100815125953.198505Z#000000#000#000000  
 modifiersName: cn=config  
 modifyTimestamp: 20100815125953Z    

Add ldif file to the LDAP configuration:
 ldapadd ­-Y EXTERNAL ­-H ldapi:/// ­-f ~/cn=samba.ldif   

Restart ldap:
 systemctl restart slapd    

Create samba config file:
 nano /usr/local/samba/lib/smb.conf    

And paste:
 ldap admin dn = "cn=admin,dc=domain,dc=edu"  
 passdb backend = ldapsam:ldap://  
 ldap ssl = off  
 ldap suffix = "dc=domain,dc=edu"  
 ldap passwd sync = yes  
 ldap group suffix = ou=Group  
 ldap user suffix = ou=People  
 workgroup = DOMAIN.EDU  
 netbios name = LDAPSERV  
 local master = yes  add machine script = /usr/sin/useradd ­-d \  /dev/null ­-g 200 ­-s /sbin/nologin ­-M %u  
 security = user  
 logon drive = H:  
 domain master = yes  
 domain logons = yes  
 preferred master = yes  
 wins support = yes  
 log level = 2  
 log file = /usr/local/samba/logs  
 comment = Home dirs  
 path = /home/%u  
 read only = no  
 create mode = 0750  
 browseable = yes  
 path = /usr/local/samba/netlogon  
 guest ok = yes  
 browseable = no  
 path = /usr/local/samba/profiles  
 writeable = no  
 guest ok = yes  
 browseable = yes  
 create mode = 0700   

Create directories and group for machines:
 mkdir /usr/local/samba/profiles  
 mkdir /usr/local/samba/netlogon  
 groupadd ­-g 200 machine    

Test config:

Change samba admin password:
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/samba/lib  
 /usr/local/samba/bin/smbpasswd ­-W    

We need samba tools to create LDAP nodes:
 cpan> install Net::LDAP  
 cpan> install Crypt::SmbHash  
 cpan> install Digest::SHA1  
 cd ~/  
 wget http://download.gna.org/smbldap­tools/sources/0.9.9/smbldap­tools­0.9.9.tar.gz  
 tar xvfz smbldap­tools­0.9.9.tar.gz  
 cd smbldap­tools­0.9.9  
 ./configure --­­with­-samba­-sysconfdir=/usr/local/samba/lib  ­--with­-samba­-bindir=/usr/local/samba/bin --sysconfdir=/etc/samba  
 make && make install    

Copy config files:
 cp ­-pr smbldap.conf /etc/samba/smbldap­tools/smbldap.conf  
 cp ­-pr smbldap_bind.conf /etc/samba/smbldap­tools/smbldap_bind.conf   

Get domain SID number:
 export PATH=$PATH:/usr/local/samba/bin  
 net getlocalsid   

Edit /etc/samba/smbldap­tools/smbldap.conf and change lines:

Edit /etc/samba/smbldap­tools/smbldap_bind.conf:
 masterPw="<ldap admin password>"    


Add library path:
 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/samba/lib    

Restart samba:
 killall smbd  
 killall nmbd  

You can check domain state:

Add user for our domain:
 useradd DOMAIN.EDU$  
 /usr/local/samba/bin/smbpasswd ­-a -­i DOMAIN.EDU  ​ (without $)    

Add users

Add user with:
 smbldap­-useradd <name>   

Then set password:
 smbpasswd -­a <name>  
Now you can join to this domain with Windows 7 client but remember to change compatibility settings.

środa, 10 lutego 2016

Joining a Windows 7 client to a samba 3 domain controller

When you want to join a domain served by a samba 3 domain controller using Windows 7, you probably will get some errors. To achieve this you must turn on some compatibility options in the Windows register.

1. Run regedit
2. Go to: HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters
3. Create (or modify) this parameters: "DNSNameResolutionRequired" = DWORD(0) and "DomainCompatibilityMode" = DWORD(1)

4. Join the domain.

niedziela, 7 lutego 2016

UEFI programming using pure assembler (32bit mode)

I was writing some small UEFI applications. UEFI is a powerful BIOS successor, which introduces a lot of features. Unfortunately not every implementations on real hardware supports all these things. I neeed only basic functionality like writing some text for test purposes and wrote small test programs using pure assembler.

In the internet you can easily find an asm code for 64 bit architecture but not for 32 bit. I shared my translated code https://github.com/eszkadev/UEFI-32bit-asm-examples

Most important file is efi.inc which describes EFI structures:
 ; EFI.inc  
 ; Based on: http://wiki.osdev.org/Uefi.inc  
 ; 2015 Szymon Kłos  
 struc int8 {  
  . db ?  
 struc int16 {  
  align 2  
  . dw ?  
 struc int32 {  
  align 4  
  . dd ?  
 struc int64 {  
  align 8  
  . dq ?  
 struc intn {  
  align 4  
  . dd ?  
 struc dptr {  
  align 4  
  . dd ?  
  ; symbols  
 EFI_SUCCESS                       equ    0  
 EFI_SYSTEM_TABLE_SIGNATURE        equ    20494249h  
 EFI_SYSTEM_TABLE_SIGNATURE2       equ    54535953h  
  ; helper macro for definition of relative structure member offsets  
 macro struct name  
  virtual at 0  
   name name  
  end virtual  
  ; structures  
  .Signature                  int64  
  .Revision                   int32  
  .HeaderSize                 int32  
  .CRC32                      int32  
  .Reserved                   int32  
  .Hdr                        EFI_TABLE_HEADER  
  .FirmwareVendor             dptr  
  .FirmwareRevision           int32  
  .ConsoleInHandle            dptr  
  .ConIn                      dptr  
  .ConsoleOutHandle           dptr  
  .ConOut                     dptr  
  .StandardErrorHandle        dptr  
  .StdErr                     dptr  
  .RuntimeServices            dptr  
  .BootServices               dptr  
  .NumberOfTableEntries       intn  
  .ConfigurationTable         dptr  
  .Reset                      dptr  
  .OutputString               dptr  
  .TestString                 dptr  
  .QueryMode                  dptr  
  .SetMode                    dptr  
  .SetAttribute               dptr  
  .ClearScreen                dptr  
  .SetCursorPosition          dptr  
  .EnableCursor               dptr  
  .Mode                       dptr  
  .Reset                      dptr  
  .ReadKeyStroke              dptr  
  .WaitForKey                 dptr  
 struc EFI_INPUT_KEY {  
  .ScanCode                   int16  
  .UnicodeChar                int16  
 struct EFI_INPUT_KEY  
  .Hdr                        EFI_TABLE_HEADER  
  .GetTime                    dptr  
  .SetTime                    dptr  
  .GetWakeUpTime              dptr  
  .SetWakeUpTime              dptr  
  .SetVirtualAddressMap       dptr  
  .ConvertPointer             dptr  
  .GetVariable                dptr  
  .GetNextVariableName        dptr  
  .SetVariable                dptr  
  .GetNextHighMonotonicCount  dptr  
  .ResetSystem                dptr  
 struc EFI_TIME {  
  .Year                       int16  
  .Month                      int8  
  .Day                        int8  
  .Hour                       int8  
  .Minute                     int8  
  .Second                     int8  
  .Pad1                       int8  
  .Nanosecond                 int32  
  .TimeZone                   int16  
  .Daylight                   int8  
  .Pad2                       int8  
  .sizeof                     rb 1  
 struct EFI_TIME  

Pointer to the EFI_SYSTEM_TABLE structure is passed to your entry function. EFI uses C calling convention and you can get it from the stack:

 format pe dll efi  
 entry main  
 section '.text' code executable readable  
 include 'efi.inc'  
     push ebp  
     mov ebp, esp  
  ; get args ( ImageHandle and SystemTable pointer )  
     mov ecx, [ebp+8]  
     mov [ImageHandle], ecx  
     mov edx, [ebp+12]  
     mov [SystemTable], edx  
  ; ... YOUR CODE  
     mov eax, EFI_SUCCESS  
     pop ebp  
 section '.data' data readable writeable  
 ImageHandle        dd        ?  
 SystemTable        dd        ?  
 section '.reloc' fixups data discardable  

Simple HelloWorld: https://github.com/eszkadev/UEFI-32bit-asm-examples/blob/master/HelloWorld.asm

EFI application binary must be in a PE format. You can compile this code with fasm. Then place it on your disc and run from UEFI Shell (for example using Virtualbox).