Monday, May 4, 2015

How 32-bit applications make system calls in 64-bit Windows

First, I'll describe how 32-bit programs make system calls in 32-bit Windows, then I'll describe how it runs in the WOW64 environment and make system calls in 64-bit Windows.

In 32-bit windows:

Executable loads kernel32.dll and ntdll.dll 
Calling the win32 API, CreateFile, ends up calling kernel32.dll!CreateFileW


kernel32.dll!CreateFileW ends up calling ntdll.dll!ZwCreateFile
ntdll.dll!ZwCreateFile moves the system call number (0x42 for ZwCreateFile) into EAX, and...

...executes the "SYSENTER" instruction, which makes the transition into the Windows kernel.

For 32-bit programs on 64-bit Windows:

Upon starting the program:
CommandLine: "C:\Users\admin\Documents\Visual Studio 2013\Projects\test\Release\test.exe"

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*c:\symbols*http://msdl.microsoft.com/download/symbols
Executable search path is:
ModLoad: 00000000`00200000 00000000`00206000   test.exe

ModLoad: 00000000`775f0000 00000000`77798000   ntdll.dll
ModLoad: 00000000`777d0000 00000000`77950000   ntdll32.dll
ModLoad: 00000000`738c0000 00000000`738ff000   C:\Windows\SYSTEM32\wow64.dll
ModLoad: 00000000`73860000 00000000`738bc000   C:\Windows\SYSTEM32\wow64win.dll
ModLoad: 00000000`73850000 00000000`73858000   C:\Windows\SYSTEM32\wow64cpu.dll
ModLoad: 00000000`773d0000 00000000`774ef000   WOW64_IMAGE_SECTION
ModLoad: 00000000`75840000 00000000`75950000   WOW64_IMAGE_SECTION
ModLoad: 00000000`773d0000 00000000`774ef000   NOT_AN_IMAGE
ModLoad: 00000000`774f0000 00000000`775ea000   NOT_AN_IMAGE
ModLoad: 00000000`75840000 00000000`75950000   C:\Windows\syswow64\kernel32.dll
ModLoad: 00000000`77330000 00000000`77377000   C:\Windows\syswow64\KERNELBASE.dll
ModLoad: 00000000`74b70000 00000000`74c5e000   C:\Windows\SysWOW64\MSVCR120.dll

Note that there are 2 "ntdll" present in the loaded modules. "ntdll32.dll" is the 32-bit ntdll from c:\windows\syswow64\, and "ntdll.dll" is the 64-bit ntdll from c:\windows\system32.

Making a win32 api call, CreateFile, in WOW64 follows this path:

- API calls kernel32!CreateFileW

- kernel32!CreateFileW calls kernelbase.dll!CreateFileW:

0:000> bp kernel32!CreateFileW
0:000> g
Breakpoint 0 hit
kernel32!CreateFileW:
7585167f ff25d4098575    jmp     dword ptr [kernel32!_imp__CreateFileW (758509d4)] ds:002b:758509d4={KERNELBASE!CreateFileW (7734c299)}

- KERNELBASE!CreateFileW calls ntdll32.dll!ZwCreateFile:


KERNELBASE!CreateFileW+0x330:
7734c5c9 8b35ac103377    mov     esi,dword ptr [KERNELBASE!_imp__NtCreateFile (773310ac)] ds:002b:773310ac={ntdll32!ZwCreateFile (777f00b0)}

- ntdll32!ZwCreateFile sets the API number (0x52 for ZwCreateFile) into EAX, and insteading of executing the "SYSENTER" instruction, it calls wow64cpu.dll!X86SwitchTo64BitMode:

ntdll32!ZwCreateFile:
777f00b0 b852000000      mov     eax,52h
0:000:x86> t
ntdll32!ZwCreateFile+0x5:
777f00b5 33c9            xor     ecx,ecx
0:000:x86> t
ntdll32!ZwCreateFile+0x7:
777f00b7 8d542404        lea     edx,[esp+4]
0:000:x86> t
ntdll32!ZwCreateFile+0xb:
777f00bb 64ff15c0000000  call    dword ptr fs:[0C0h]  fs:0053:000000c0=00000000
0:000:x86> t
wow64cpu!X86SwitchTo64BitMode:
73852320 ea1e2785733300  jmp     0033:7385271E

wow64cpu!X86SwitchTo64BitMode makes a inter-segment jump into the the segment with selector 0x30 (the 3 at the end indicates that it is a ring 3 segment, a.k.a. user-land) Before this jmp, the code is running on segment 23. This segment is running in 32-bit mode (long mode set to 0):

0: kd> dt _KGDTENTRY64 0xfffff800`00b93000+20 /b
nt!_KGDTENTRY64
   +0x000 LimitLow         : 0xffff
   +0x002 BaseLow          : 0
   +0x004 Bytes            :
      +0x000 BaseMiddle       : 0 ''
      +0x001 Flags1           : 0xfb ''
      +0x002 Flags2           : 0xcf ''
      +0x003 BaseHigh         : 0 ''
   +0x004 Bits             :
      +0x000 BaseMiddle       : 0y00000000 (0)
      +0x000 Type             : 0y11011 (0x1b)
      +0x000 Dpl              : 0y11
      +0x000 Present          : 0y1
      +0x000 LimitHigh        : 0y1111
      +0x000 System           : 0y0
      +0x000 LongMode         : 0y0
      +0x000 DefaultBig       : 0y1
      +0x000 Granularity      : 0y1
      +0x000 BaseHigh         : 0y00000000 (0)
   +0x008 BaseUpper        : 0xffff
   +0x00c MustBeZero       : 0xcff300
   +0x000 Alignment        : 0x00cffb00`0000ffff

This jmp will jump to the segment 33, which is set to long-mode, a.k.a. 64 bit mode:

0: kd> dt _KGDTENTRY64 0xfffff800`00b93000+30 /b
nt!_KGDTENTRY64
   +0x000 LimitLow         : 0
   +0x002 BaseLow          : 0
   +0x004 Bytes            :
      +0x000 BaseMiddle       : 0 ''
      +0x001 Flags1           : 0xfb ''
      +0x002 Flags2           : 0x20 ' '
      +0x003 BaseHigh         : 0 ''
   +0x004 Bits             :
      +0x000 BaseMiddle       : 0y00000000 (0)
      +0x000 Type             : 0y11011 (0x1b)
      +0x000 Dpl              : 0y11
      +0x000 Present          : 0y1
      +0x000 LimitHigh        : 0y0000
      +0x000 System           : 0y0
      +0x000 LongMode         : 0y1
      +0x000 DefaultBig       : 0y0
      +0x000 Granularity      : 0y0
      +0x000 BaseHigh         : 0y00000000 (0)
   +0x008 BaseUpper        : 0
   +0x00c MustBeZero       : 0
   +0x000 Alignment        : 0x0020fb00`00000000

This inter-segment jump is the actual transition from 32-bit mode to 64-bit mode.

After this transition, the cpu lands at address 7385271E, which is wow64cpu!CpupReturnFromSimulatedCode. It calls wow64cpu!ServiceNoTurbo:

wow64cpu!CpupReturnFromSimulatedCode:
00000000`7385271e 67448b0424      mov     r8d,dword ptr [esp] ds:00000000`0014fc9c=777f00c2
00000000`73852723 458985bc000000  mov     dword ptr [r13+0BCh],r8d ds:00000000`001bfddc=777eface
00000000`73852723 458985bc000000  mov     dword ptr [r13+0BCh],r8d ds:00000000`001bfddc=777eface
00000000`7385272a 4189a5c8000000  mov     dword ptr [r13+0C8h],esp ds:00000000`001bfde8=0014f98c
00000000`73852731 498ba42480140000 mov     rsp,qword ptr [r12+1480h] ds:00000000`7efdc480=00000000001be840
00000000`73852739 4983a4248014000000 and   qword ptr [r12+1480h],0 ds:00000000`7efdc480=00000000001be840
00000000`73852742 448bda          mov     r11d,edx
wow64cpu!TurboDispatchJumpAddressStart:
00000000`73852745 41ff24cf        jmp     qword ptr [r15+rcx*8] ds:00000000`73852450={wow64cpu!ServiceNoTurbo (00000000`73852749)}

Which calls wow64.dll!Wow64SystemServiceEx:

wow64cpu!ServiceNoTurbo+0x27:
00000000`73852770 ff150ae9ffff    call    qword ptr [wow64cpu!_imp_Wow64SystemServiceEx (00000000`73851080)] ds:00000000`73851080={wow64!Wow64SystemServiceEx (00000000`738cd0b8)}

Which calls whNtCreateFile in wow64.dll:

wow64!Wow64SystemServiceEx+0xd4:
00000000`73bad18c 41ffd4          call    r12 {wow64!whNtCreateFile (00000000`73bbc0f0)}

Which calls NtCreateFile in the 64-bit ntdll.dll:

wow64!whNtCreateFile+0x109:
00000000`73bbc1f9 ff154958feff    call    qword ptr [wow64!_imp_NtCreateFile (00000000`73ba1a48)] ds:00000000`73ba1a48={ntdll!NtCreateFile (00000000`7791e120)}

Which finally calls the "SYSCALL" instruction to transition to the kernel.

ntdll!NtCreateFile:
00000000`7791e120 4c8bd1          mov     r10,rcx
00000000`7791e123 b852000000      mov     eax,52h
00000000`7791e128 0f05            syscall
00000000`7791e12a c3              ret

Wednesday, March 4, 2015

Disabling Ctrl Alt Del in Windows 7 32-bit and Windows 8.1 32-bit

I'm surprised there is such scarce documentation on this topic, and even more surprised that I can't find a working implementation to disable Ctrl+Alt+Del. So I reverse engineered and found it out!

TLDR: Here's the executable. Note: you have to run it as the user nt authority\system. The easiest way is to run the command psexec -i -s -d DisableCtrlAltDelPatchWinlogon.exe in an elevated command prompt.

TDLR programmers: here's the code.

If you like to read about my process:

First, I read up the background information on Special Attention Sequences, which include Ctrl+Alt+Del (CAD). I found that 'When Winlogon encounters a SAS event or when a SAS is delivered to Winlogon by the GINA, Winlogon sets the state accordingly, changes to the Winlogon desktop, and calls one of the SAS processing functions of the GINA.' My first thoughts are, maybe I should reverse engineer the GINA, but then I found out the GINAs only exist for Windows XP and below. 'In Windows Vista, the GINA scheme has been replaced with a system of Credential Providers, which moves some of that functionality into WINLOGON itself...'

So now I know that Winlogon.exe is in charge of CAD, and it switches to the Winlogon desktop whenever it encounters a CAD, if I place a breakpoint at the time that it does a desktop switch, I could potentially see all the preceding functions and stack calls. So I took a look at the imports of Winlogon.exe, and sure enough, I found user32!SwitchDesktop. Its time for WinDbg!

I kernel debugged my Win 7 x86 machine and broke into the context of Winlogon.exe:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
…
PROCESS 8520f530  SessionId: 1  Cid: 018c    Peb: 7ffd7000  ParentCid: 0158
    DirBase: 197a4000  ObjectTable: 9506ead0  HandleCount: 123.
    Image: winlogon.exe
…

kd> .process /i 8520f530  
You need to continue execution (press 'g' ) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
82893d00 cc              int     3

Then I placed a breakpoint on SwitchDesktop:

kd> bp user32!SwitchDesktop
kd> g

Then I triggered CAD:

Breakpoint 0 hit
USER32!SwitchDesktop:
001b:77d1476b 8bff            mov     edi,edi
kd> kv
ChildEBP RetAddr  Args to Child              
0023fcec 01002147 000000b8 0103c144 002b1ff8 USER32!SwitchDesktop (FPO: [Non-Fpo])
0023fd04 01002d04 000000b8 00000001 00000000 winlogon!ResilientSwitchDesktopWithFade+0x2a (FPO: [Non-Fpo])
0023fd60 01014387 00000000 0023fd88 00000000 winlogon!CSession::SwitchDesktop+0x1c0 (FPO: [Non-Fpo])
0023fd78 010266c8 0103c378 00000000 00000000 winlogon!WlAccessibilitySwitchDesktop+0x1b (FPO: [Non-Fpo])
0023fdd8 01028f8a 0006fd98 000003ff 0103c144 winlogon!HandleSecurityOptions+0x48 (FPO: [Non-Fpo])
0023fdec 0100222f 0006fd98 77f32ba4 000a1a90 winlogon!WLGeneric_CAD_Execute+0x5e (FPO: [Non-Fpo])
0023fe04 77ed2661 0023fe64 0006fd88 000a1a90 winlogon!StateMachineWorkerCallback+0x67 (FPO: [Non-Fpo])
0023fe28 77ef0842 0023fe64 000a1af0 77dbb0c4 ntdll!TppWorkpExecuteCallback+0x10f (FPO: [Non-Fpo])
0023ff88 77e33c45 00092250 0023ffd4 77f237f5 ntdll!TppWorkerThread+0x572 (FPO: [Non-Fpo])
0023ff94 77f237f5 00092250 77dbb098 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
0023ffd4 77f237c8 77ef03e7 00092250 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
0023ffec 00000000 77ef03e7 00092250 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

So here's a list of all the functions I should investigate. WLGeneric_CAD_Execute turns out to be the function that I was looking for, so all I had to do is the patch the starting code in that function to get it to return immediately, and CAD has been disabled!

Wednesday, February 25, 2015

Enabling SMEP in VMware Windows 8.1 guest

I have many VMs on my Windows 8.1 64-bit host. I have both Windows 8.1 32-bit and Windows 8.1 64-bit as guests. I noticed that SMEP is enabled on my 32-bit guest, but not my 64-bit one.

SMEP is not enabled.

So I tried something: I checked the box under VM settings -> Hardware -> Processors -> Disable acceleration for binary translation.

Disabling acceleration for binary translation

And SMEP now works on my 64-bit Win 8.1 guest!


SMEP enabled after disabling acceleration.


Wednesday, November 5, 2014

Using Yowsup to get groups and group information

Took me a while to figure this out.

I had a particularly annoying problem with Python: it thinks that I'm giving it 14 parameters when I'm giving it 2. In particular, I had to add dummy parameters to sendGetGroups and sendGetGroupInfo inside connectionmanager.py so that I can pass arguments to them correctly.

Using Yowsup to get information about a group

Using Yowsup to get the list of all groups the user is participating in

Files:
Yowsup\connectionmanager.py
Examples\GroupInfoClient.py
Examples\GetAllGroupsClient.py
yowsup-cli

Tuesday, November 4, 2014

Using Yowsup to send contacts

Contacts are referred to as Vcards inside the library, so I'll refer them as Vcards from the next sentence on. Vcards work in the same way as location, as both of them do not need the media request, media upload, send media chain. A call to message_vcardSend will do. message_vcardSend accepts 3 parameters: JID of person to send to, data, and name. I had no idea what data is, so I started off writing a listener for Vcards instead, to learn the format of the data parameter.


I've included the files for the listener below.

Following the format as shown above, I wrote the code for sending Vcards. It generally works, but occasionally, the send doesn't get through and the receiver will receive nothing. If anyone can pinpoint why this happens please enlighten me.




Files:





Monday, November 3, 2014

Using Yowsup to send location

Previously when sending images, video and audio, the flow goes like this:

Request media upload -> request success -> upload -> upload success -> send url of uploaded media to other people

I realised that sending location does not follow this pattern. All it requires is calling message_locationSend with the correct parameters and it'll work.

Nevertheless, I had to fix up connectionmanager.py a bit as it does not include the "name" attribute, and it crashes my Whatsapp on iOS everytime the location is sent (as of 4 Nov 2014)...the updated connectionmanager.py is posted below. The line that is changed is marked with #sirpoot

If you send with a name, longitude and latitude you'll get this:





If you send with an empty name, you'll replicate the same thing as what Whatsapp on iOS does:






 Files:
Examples\LocationUploaderClient.py
Yowsup\connectionmanager.py
yowsup-cli





Sunday, November 2, 2014

Using Yowsup to send audio and video

It works.

Sending audio and video files work in the same way as sending images. It begins with a call to media_requestUpload with the hash, a string of the type of file to upload, and the filesize as arguments, and once the request succeeds, the client has to use MediaUploader to upload the local file, and finally when the upload completes the client can then send the URL to friends using the method message_imageSend, message_audioSend, and message_videoSend for images, audio files and video files respectively. The only difference in the API for these 3 methods are: message_audioSend does not have a preview as argument, while message_videoSend and message_imageSend both have a argument for the preview (which can be None).

Please note that most of the audio and video uploader code is copy-pasted from the image uploader, and I haven't wrote in preview code for the video uploader due to the infinite variety of video formats out there. This code is more for people to look at and see how it works than to be used in production.

Examples\VideoUploaderClient.py
yowsup-cli

Tested with .mp3 and .wav for audio, and .mp4 for video.

Using Yowsup to send audio and video files

Saturday, August 16, 2014

Multi-monitor gaming

Managed to dig out spare monitors from the storehouse, now I can finally play games on 3 monitors!

My graphics card is the Chinese Colorful GTX 750. It has 3 ports at the back, 1 VGA, 1 DVI, and 1 HDMI. I used 1 HDMI to DVI cable for the first monitor, 1 DVI to DVI for the 2nd, and 1 VGA to VGA for the third monitor.

Here's the outcome:

I now have one super wide desktop. Panorama wallpapers look absolutely awesome!

3-monitor Payday 2. All 3 monitors have 4:3 aspect ratio

3-monitor Payday 2



In this experiment, I tried to determine if the same monitors (the same aspect ratio) is needed for 3-monitor gaming to work. For this and the following photo I replaced the center monitor with a widescreen one (16:9 aspect ratio). To my surprise, the center monitor isn't skewed or stretched; it worked perfectly!

Aspect ratios of monitors from left to right: 4:3, 16:9, 4:3. No problems with the graphics!

After playing several rounds of Payday 2 I discovered that the side monitors really help in spatial awareness. I can remember map layouts much better with the side monitors around!

Tuesday, August 12, 2014

Using Yowsup to send pictures to a group

So, I intended to send pictures to my whatsapp group...these are the steps I took.

1. Buy a cheap SIM card, take note of that number
2. Edit the config file, use yowsup-cli to register using that phone number and input the subsequent verification code

Register a Whatsapp account using phone number


3. Extend the ListenerClient to listen for group messages, ask one of my groupmates to send the group a test message. This allows me to obtain the JID of the group.

Listen for group messages to obtain JID of the group

4. Extend CmdClient.py and fix it, and add in my own additions to yowsup-cli to be able to send

Sending images to group chat


Here are all my files at the end:

Examples\GroupListenerClient.py
Examples\UploaderClient.py
Examples\CmdClient.py
yowsup-cli


References:

Using the yowsup-cli, registering a new account
http://hacktracking.blogspot.sg/2013/02/yowsup-cli-send-whatsapp-messages-from.html

Getting JID of the group
https://github.com/tgalal/yowsup/issues/162

Sending images by SamsonBox
https://github.com/tgalal/yowsup/issues/178

Creating preview images
https://github.com/tgalal/yowsup/issues/35#issuecomment-41364453



Tuesday, July 8, 2014

Wierd VM behavior

My Windows 7 virtual machine, which has 2GB of RAM allocated to it, is extremely laggy, to the point that opening a folder will take minutes. Surprisingly, it became all smooth and quick when I decreased its RAM allocation to 1GB. Intrigued, I used Process Explorer to look at some of its stats.

Win7 VM with 2GB of RAM

When the VM had 2 GB of RAM, its CPU usage is mostly zero. In addition, even when idle, it's performing about 200 Page faults per second.

Win7 VM with 1GB of RAM
When the VM had 1 GB of RAM, it used 1.2GB for its working set, the CPU is hard at work, and page faults are close to non.

Wierd... I have no idea why.

Monday, May 26, 2014

timeBeginPeriod

Was reading how the use of timeBeginPeriod to increase system tick frequency could lead to a shorter battery life (read here) ...decided to investigate how timeBeginPeriod function interacts with Windows 8, since Windows 8 uses tickless kernel and theoretically has no relations with system timer ticks. From MSDN, timeBeginPeriod resides in winmm.dll. There are 2 versions on winmm.dll on my Win 8 machine, one under c:\Windows\SysWow64 and one under c:\Windows\system32.

timeBeginPeriod in c:\Windows\SysWow64\winmm.dll:

timeBeginPeriod calls an imported function, timeBeginPeriod@4

timeBeginPeriod@4 belongs to api-ms-win-mm-time-l1-1-0.dll

timeBeginPeriod@4 in api-ms-win-mm-time-l1-1-0.dll is an empty function
timeBeginPeriod in c:\Windows\system32\winmm.dll uses the same flow, importing the function timeBeginPeriod@4 from api-ms-win-mm-time-l1-1-0.dll:

x64 api-ms-win-mm-time-l1-1-0.dll uses the same function for multiple exports

And that one function is empty

Hence, I've verified that timeBeginPeriod does not work in Win 8...so why is Win 8 battery life still so weak?!




Monday, May 19, 2014

How Procmon works




Out of curiosity I looked under the hood of the tool that lets you look under the hood of other programs.

To be able to monitor so many system functions at once, Procmon probably uses a driver to do that. So I went looking for Procmon's driver using GMER, and found PROCMON23.SYS.




I didn't see PROCMON23.SYS inside the Sysinternals directory, so I guess it'll be inside the PE structure. Sure enough, when I use PE Explorer to open up Procmon, I found it inside the BINRES directory in the RESOURCE section.



Extracted out the driver, and analysed using NikPEViewer. It's a 32 bit driver.


Then proceeded to analysis using IDA. It registers itself as a filter driver...



Creates a filter communication port at \ProcessMonitor23Port and starts the filter.



Procmon 64 bit

When running Procmon in 64-bit systems, another process called Procmon64.exe is created. This isn't found anywhere in the Sysinternals folder.

Procmon in 64-bit Windows
This implies that its 64-bit image is being stored in its 32-bit executable. Hence, I looked up the second entry under the BINRES section, and sure enough, it's a PE file:

Location of Procmon 64 bit image

Procmon's 64 bit image

Initially I thought it was the 64-bit Procmon driver...turned out that it is the 64-bit Procmon executable. And of course, the 64-bit driver is hidden inside the 64 bit executable's resource section.

Procmon 64 bit driver





Friday, May 16, 2014

How to turn off monitor screen

Found a small program called Turn Off Monitor, decided to investigate how it works.

 Used IDA to open it, turned out to be a .NET exe. Opened it using Dotnet IL Editor instead.

Main code:


Seems like the only API call needed is SendMessage. ldc.i4.m1 means push -1 to stack, so the API call is SendMessage(-1,a,b,2).

SendMessage belongs to user32.dll:


Second argument, a is 0x04000003:


Third argument, b is 0x04000004:


So the only API call needed turned out to be user32!SendMessage(-1,0x04000003,0x04000004,2).

Tuesday, September 10, 2013

Kindle digital photo frame part 5: testing and finalizing

The scripting and programming is mostly complete. Time to test the Kindle. For the purpose of testing, I set the Kindle to change screensavers every 5 minutes instead of every 3 hours. It works flawlessly for hours at a time, then fails. It always fails in the same way: displaying no picture in screensaver mode. Even manually pressing the button power twice does not solve it. Perhaps the Blanket program crashed or something, I don't know, but it fixes itself after a restart.

After hours of debugging I still cannot figure out what the problem is. Decided to call it quits, but added a recovery option should that happen. I installed KUAL and kterm, so that after a reboot I can manually run my screensaver changing script again.

Finally, I decided to consolidate both the script to change screensavers and that to download images. Here's the final masterpiece:

I've reset the screensavers to change every 3 hours instead of 5 minutes. It'll still be a few days before I present this to my girlfriend, a final few days to test and make sure it works perfect!

Kindle digital photo frame part 4: downloading pictures from the net + more screensaver problems

Even more problems came to bite me. I had intended to use wget with some options like -r to easily download all the images that I have listed on the front page of my CakePHP backend. However, Kindle's busybox wget is quite primitive; it does not have so many options, and I am forced to perform grep, awk and a lot more scripting to download the pictures that I uploaded. Here's the code:

In addition, Kindle renames screensavers after restart. All the photos inside the screensavers folder will be renamed to bg_xsmall_ssXX.png. That implies that a maximum of 100 photos are allowed. In addition, if the order of the photos is to be randomized via creating a file called "random", all the photos' filenames will be randomized again upon bootup, meaning I won't be able to tell if /var/local/blanket/screensaver/last_ss points to a photo or downloaded image.

In view of these, I decided to rotate the photos myself by placing one 1 photo inside the screensavers directory: bg_small_ss00.png, and replace that file everytime I change my screensaver. As usual, Busybox is so limited in functionality that I have to go through massive scripting just to choose a random photo or determine a random number. This is my updated screensaver-changing script:

Monday, September 9, 2013

MK 809 III Android mini PC

The MK 809 looks like an oversized thumb drive that plugs into a HDMI port, but it is a full fledged android pc. I was quite excited when I saw it on sale on Qoo10; I've been wanting a powerful arm computer to test BOINC on, and the MK 809 III has 4 cores, fits into my palm and uses a phone charger. Sweet!

I'm more bitter about the price though. The Qoo10 seller was selling at S$96 including shipping fees. That's out of my budget. Decided to source upstream, and found it alibaba.com, selling for US$45 a piece. However, there is a minimum order of 10. Thus finally, I went to it's sister site, aliexpress, and found one selling at US$57. Perfect!

I wonder if an Android OS can be used for programming?

Would update when the item arrives.

Final Fantasy Fables: Chocobo's Dungeon

Just cleared the 100 levels dungeon in Chopin's dungeon for the Wii. I killed the boss at level 71, and was level 8 dragoon wearing a genji's  talon+79 and king's saddle+57 when I did it. All I did was spam Holy Lance and Gungnir, drink ethers like crazy, and ate just one Phoenix down when near death.

Phew, that was fast!

Sunday, September 8, 2013

Kindle digital photo frame part 3: Changing screensavers every 3 hours

Getting the Kindle to change its screensaver is as simple as running /usr/bin/powerd_test -p twice. The script to do so:

I wanted the screensaver to be changed every 3 hours, excluding nighttime. It's a matter of appending to /etc/crontab/root:

Then I ran into a pesky problem. The screensaver changer works if I ran it manually. It doesn't work via the cron job. Or rather, I discovered that the Kindle goes to sleep after 1 minute in screensaver mode.

After fiddling with /usr/bin/powerd_test -s for quite some time I discovered the following. The Kindle has 4 power levels: Active, Screen Saver, Ready to suspend, and sleep. Active stays on for 10 minutes, Screen Saver stays on for 1 minute, and Ready to suspend stays on for 5 seconds. This is my log:

I can wake up my Kindle via the command "lipc-set-prop com.lab126.powerd wakeUp 1" provided it is in one of those 3 states. To try and suspend my Kindle in the "ScreenSaver" or "Ready to suspend" state for as long as possible, I investigated the seemingly useless property, deferSuspend, from com.lab126.powerd. When you run it, it gives the error:

com.lab126.powerd failed to set value for property deferSuspend (0x8 lipcErrNoSuchProperty)

I discovered that the property can only be set DURING THE READY TO SUSPEND STATE. That means after 11 minutes of leaving the Kindle alone I have a 5 second window to change the time left in "Ready to Suspend" state. See my logs:

My screensaver changing script ended up as:

Digital photo frame: Kindle Touch vs Kindle Keyboard

In the midst of hacking my newly acquired Kindle keyboard I got myself another Kindle: this time a Kindle Touch 3G. I intended to use one as the photo frame and another as my ebook reader.

Now, which to use for my digital photo frame?

The Touch, being slimmer without a keyboard, would be easier to conceal within a frame. Not to mention that my Keyboard came with a leather case and I like it a lot. The Touch seems like a natural choice.

Until I got down to hacking it. After the usual jailbreaking and stuff, I found out that the Touch only supports PNG. This, while my Kindle keyboard can support jpg, gif and images of all shapes and sizes. Ended up using the Kindle Touch anyway.

Kindle digital photo frame part 2

Now that I can SSH into the Kindle I need to figure out the functions that I need. I want the Kindle to cycle through me and my gf's photos every 3 hours. Apart from that, I want to be able to upload photos of cute cats or love messages onto the internet, and those will show up, ONLY ONCE, on the Kindle.

For cycling photos, I need to:
  1. Wake up the Kindle from sleeping
  2. Put it to sleep again.

(1) is easy to find. The command, lipc-set-prop com.lab126.powerd wakeUp 1, will wake up the Kindle. (http://www.mobileread.com/. forums/archive/index.php/t-160328.html) Fortunately, cron works even when the Kindle is sleeping, so cycling photos is definitely possible.

(2) took me a while to find. The command is, /usr/bin/powerd_test -p . (http://www.mobileread.com/forums/showthread.php?t=220810) It works for waking up the Kindle as well, so now I can simply cycle my photos by running this command twice!

For displaying my uploaded pictures, I need to:
  1. Setup a server backend for uploading images
  2. Periodically downloading them into the Kindle
  3. Display the images occasionally, deleting them after they've been displayed.

For (1), I can simply use OpenShift and CakePHP to setup a backend for uploading and storing images. I've familiarized myself with that setup thanks to a previous competition, so no worries here.

(2), I can simply write a script for downloading the images from my backend and add it to crontab. I can even turn on wireless using cron, no issues here.

(3), I had no idea to detect which image is being displayed on screen. Thankfully, I found this page https://github.com/yifanlu/OpenBlanket/blob/master/screensaver.c, line 363 of the code shows that the last screensaver displayed is stored at "/var/local/blanket/screensaver/last_ss". I can use this while waking up the Kindle, to delete the images shown before.

Stay tuned to the next part!