How to easily test an N-CHANNEL or P-CHANNEL MOSFET using just a multimeter

You should have noticed that most multimeters come with a function to test BJT transistors, but none has a function to test the today’s more common MOSFETs

Here are the steps to test an N-CHANNEL mosfet with just a multimeter ( applies to P-CHANNEL too, just swap + and – ), of course the MOSFET has to be disconnected completely.


  1. Make sure you are not wearing shoes and so that you don’t have any electrostatic charge, FETs are very delicate to ESD.
  2. Now touch with your finger both Gate and Source terminals, this will make sure that the gate is uncharged
  3. Put your multimeter in diode/continuity test mode ( beep mode )
  4. Touch with the negative lead the source pin, and with positive lead the drain, it should not beep and show > 999 ohm, if there’s current flowing, after making sure again that gate is discharged, the MOSFET is damaged.
  5. Touch with the negative lead the source pin and with positive lead the gate pin, no current should flow, if current flows it means that the oxide layer between gate and substrate or N junctions has been broken by a gate-source overvoltage or ESD, trash the mosfet if that is the case.
  6. Now WITHOUT touching the gate terminal at all, touch the drain pin with positive lead and source pin with negative lead, you should get the multimeter to beep and a very low resistance reading

Finally, before trashing any mosfets, make sure that the method works with most of them using your multimeter ( there may be some multimeters that use too low voltage in continuity test mode and thus not reaching Vt threshold of the mosfet ).
To avoid ESD damage always store your MOSFETS with all pins joined together using aluminum foil or copper strands.

Installing OpenWRT on SITECOM WL-326

The SITECOM WL-326 is an ethernet+3g router featuring 300 Mbps wireless and an usb port to connect a 3G modem.

This device is not officially supported by OpenWRT and not very common, so there’s basically zero info on it at the moment.

First thing is to find out which SoC it uses, since it is covered by an heat spreader, best idea that does not involve the risk of destroying the board is connecting an USB-TTL adapter to the serial port which is visible on the photos.

Luckly contrary to most cases, the PCB has already written on it which pins are RX,TX,GND, so it’s just matter of soldering a female o male strip header, and connect it to the adapter.

Serial port settings are 57600 8N1, and when connecting the power to the device, it’s immediately visible that it is a rebrand of another device, the ESR-6670
Still no luck, it’s not supported either, but at least now we know what SoC it uses, which is Ralink 3052.

Now the tricky part, bootloader only shows one option, contrary to most supported routers

So the only option is just to try it, worst case scenario if it goes wrong we’ll have to reverse engineer the (likely) jtag connector visible on the photo.

This command will ask you some parameters, first one is the router IP, just hit enter ( leaving it as it is )
second one is the TFTP server IP, a default one will be shown.

Now connect an ethernet cable between a LAN port and your machine and ifconfig it to the router ip address

ifconfig eth0 up

or something like that.

Now you can hit enter, and then it will ask the linux kernel filename, which is WRONG, that’s not the linux kernel filename but the uImage filename.

Now the hard choice, finding a similiar enough device to flash this one with, and cross finger that it does not blow up, i’ve choosen the wr512 because it has too an usb port and an ethernet so, it’s worth trying.

So download and rename it to something sane, like /home/dev/rd.bin

Now, start a tftp server, quickiest way without spending 15 mins configuring with xinetd or crap like that is

dnsmasq –enable-tftp –tftp-root=/home/dev -d

If it fails because of port already in use, append -p 3244

If it started succesfully, enter the choosen filename ( rd.bin or whatever it is ) on the serial console and hit enter, now it should flash it and reboot, but you are not done yet, because this is an image designed to work only on RAM , so any config change will NOT be saved.

But since you should have an openwrt console now and the LAN ports configured to, ifconfig your machine’s interface to


Notice that now the downloaded file has “sysupgrade” in it and not initramfs-uImage.

Now from the serial console do

scp yourmachineuser@ /tmp/

Once done ( and completed succesfully of course ), do

sysupgrade -v /tmp/openwrt-15.05-rc2-ramips-rt305x-wr512-3ng-4M-squashfs-sysupgrade.bin

It will take like a min or two and then reboot automatically, after the reboot you will have the router at again.

Now login to LuCI interface, go to Network->Switch and you should see two vlans configured , vlan1 which is lan configured with the first port untagged and vlan2 which is wan configured to some other port untagged.

Now change on vlan1 the first port ( left to right ) , to off , and on vlan2 the first port ( same as vlan1 ) to untagged, and click save & apply.
That’s because the router of which we flashed the firmware has the switch connected differently.

That’s it now you are done , you can configure wireless and other stuff, just forget about 3G unless you replace flash memory, because it is likely that there’s not enough space on flash ( unless you build a version without LuCI and with 3g and then configure with CLI ).

Update: It’s possible to install 3g packages and still have 52 kbytes free, not tested because i don’t have an USB 3g modem handy

Converting movies to 60 fps on linux ( with wine )

You may have heard of SVP project , if not visit their website .

SVP in a first pass calculates the motion vectors for the frame ( the direction and velocity that every object in the video has moved with ), and then on the second pass it generates intermediate frames.
With that technique it can generate the intermediate frames between each frame of the original video, like when going from 24fps to 60fps.

As you have seen SVP is only for windows and there’s not any guide to easily use it under Linux, but it can be used under linux too and it’s not much difficult.

!!!IMPORTANT : The method shown here does not work with ubuntu because of some unknown wine build bug 

First of all, download the archive here , install wine and ffmpeg.

Unpack the archive in your home directory , i.e you should have at the end /home/yourusername/60fps

then do

wine wineboot
ln -sf $HOME/60fps $HOME/.wine/drive_c/60fps
wine AviSynth.exe

Follow the instructions of the installer( just click next ,next… finish)

Then edit script.avs and change FFMpegSource2 filename to your source movie if you want to specify a path outside drive_c , /a/b/c becomes Z:abc and save it.

Now you can launch x264:

If you need to , adjust bitrate and preset to suit your needs.

Now it should start interpolating and reeencoding the video, it will take a lot of time if you don’t have an highend machine, but x264 is heavy, nothing can be done about it.

After that command you should end up with the interpolated video without sound, to re-add sound you can use ffmpeg

ffmpeg -i x264output.mp4 -itsoffset 0.4 -i originalfile.mp4 -c:v copy -c:a aac -strict -2 -map 0:v:0 -map 1:a:0 outputfilewithsound.mp4

There too, if needed, adjust itoffset ( audio delay offset , interpolation seems to add a delay , still have to figure out why ).

After that you should have the movie with audio and 60 fps, have fun!

A very simple internet of things system to control lights and other stuff

In these days i’ve worked on how to create a system that allows me to turn on and off lights or appliances at home with minimal cost and complexity, and there it is:

Each node (ESP-01 ESP8266) with nodemcu firmware and the init.lua script from esp8266 folder of my repository has two outputs and can control two appliances.
A node has commands to retrieve name , unique identifier and current state, and to set the state, all that happens via UDP packet.

At first i tried, especially for discovery purposes to use UDP broadcast packets, but it seems that the module has some bug that makes the reception of broadcasts very unreliable, so at last i resorted to try to send a command to query status for each ip address specified in the subnet, like for, it would be to

The server which runs on an ARM board like a raspberry or a beaglebone takes care of the authentication of the clients from the internet ( the ESP8266 modules have no authentication , they rely on the safety of the network, so avoid passwords like “password” or “0123456789” ).

When first started the server creates a self signed certificate to use with HTTPS and a random password, then when the user connects to the webserver from a local ip address a qrcode is displayed to configure the android application.

The QR Code contains the public ip address , the port , the password and the sha1 fingerprint of the certificate, so that even if it is self-signed, it can be verified by the application to prevent man in the middle attacks.

The servers also takes care of enforcing state on the nodes, especially when a packet is lost or when the node for some reason loses power, at each discovery the state is compared and if not equal it will be resent again until the node status matches.

That’s it, with barely 200 lines of python and a trivial android app you can safely control your house from where you want.

Asus eeePC 1005PE LVDS Cable pinout

I’m posting this pinout, because it can’t be easily found, and using a multimeter it takes a lot to figure out, like it did for me

MB Connector Panel back connector Description
1 2 3.3VDD
2 4 EDID eeprom power ( 3.3V)
3 6 EDID eeprom CLK
4 7 EDID eeprom DATA
5 28 VDD_EN ( Active high, 3.3v)
6 30 VLED_EN (Active high, 3.3v)
7 22 GND
8 8 LVDS Channel 0 –
9 9 LVDS Channel 0 +
10 11 LVDS Channel 1 –
11 12 LVDS Channel 1 +
12 14 LVDS Channel 2 –
13 15 LVDS Channel 2 +
14 22 GND
15 17 LVDS Clock –
16 18 LVDS Clock +
17 1 GND
18 5 Backlight PWM ADJ
19 25 Led VCC ( 5V )
20 24 Led VCC ( 5V )

If you are planning to reuse the panel with an MT6820 board, set the panel voltage to 3.3volts , connect 3.3VDD and VDD_EN together, and connect all the gnd pins to gnd too.
About the backlight, for me it worked leaving VLED_EN open ( unconnected ) and ADJ connected to the BL pin of the mt6820 ( brightness , unless i’ve swapped for error the pins , does not seem to work )
The whole thing will draw about 1A @ 5V, so if you get an Y cable with a switch ( to prevent the mt6820 from powering on too early ), you can run it from two usb ports

The correct jumper configuration for the board is with only A closed , and all other open

How to do transparent bridging / repeater on OpenWRT with an Atheros card

What you need

  • An access point running OpenWRT and supporting 4 address mode ( WDS )
  • Another access point running OpenWRT and supporting both multi-ssid and 4 address mode ( or only 4 address mode if you want wifi->ethernet bridge )

Setting up the main access point

First of all , you need to setup the main access point , to do that , once openwrt is up and running, login to the web interface and go to “Wifi” section
Then , on the Wifi page , if needed remove any existing SSID and then add a new one
Once you have done here, click save and apply to create the new access point

Setting up the repeater

As with the main access point , login and go to Wifi section, remove any existing SSIDs / Client and then click “Scan”
Once you get the scan results( it can take up to 45 secs ) , select the network you are interested in , and click “Join network”
Once done click submit
When done with changing to client (WDS) and if needed setting up security , click “Save” , not save and apply , not yet
Now you have to create an access point ssid , to do that repeat the steps on the main access point , but when selecting the network , instead of choosing lan , choose repeater or whatever you entered when creating WDS Client interface , and the click Save and Apply and enjoy your openwrt based repeater

Quick test of NVA3 series reclocking with nouveau and comparison with NVIDIA drivers

These months there has been a lot of work on reclocking support for NVA3 nvidia cards by Roy Spliet on the opensource nouveau drivers.

Since i own a Geforce 210 GT i’ve decided to give it a try with some benchmark and the results are quite good

The reclocking of these cards is still very unstable, to have higher chance of success in reclocking, use an fbconsole and not the terminal from some composited environment like gnome-shell.

First game i’ve tested is tesseract, which is an graphically upgraded version of sauerbraten

Nouveau , when reclocked to highest performance level, can get very near to NVIDIA Proprietary driver, maybe with bleeding edge mesa , it could actually reach it.
Second game tested is Openarena :
Also on this one, performance suffered a great boost from reclocking, on that card 07 corresponds to boot frequencies, so before RSpliet’s work, only 07 was available.

Gpu test also , except some tests gave same results

Pixmark Volposition and GiMark , both failed and caused nouveau to crash

Meantime i’m downloading other games and i’m going to test also a geforce GT330 m from my sony vaio notebook , once it is reclockable to highest performance level.

Alcor UFD Controller Hacking update 2

In these days between some exercises for a microeconomics exam , i’ve continued to work on reverse engineering the Alcor 698x UFD microcontroller, and i’ve got another poor quality Alcor based flash drive from a friend , so now i’ve an 8 GB one , and a 4 GB one.

I’ve started , with the help of wireshark , usbmon and a virtual machine running windows with USB forwarding by SPICE , reverse engineering the format of the various vendor specific commands that are sent to the flash drive.

But while working on it i’ve encountered a serious problem , the Linux kernel scsi implementation removes the 3 MSBs from the 2nd byte of the SCSI commands , which in our case , breaks various commands , for example , 0x51 directed at LUN 0 , would become 0x11.

The interesting commands now are two: 0x82 and 0x81 , they are used to download and upload configurations to the flash drive.

The 0x81 command is used with that specific CDB

0x81 , 0x00 0xff , 0x00 , 0x00 , 0x00 , 0x00, 0x00 ,0x00 ,0x00 ,0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 

Then it takes 512 bytes of data that contains the actual configuration, below there’s an example of that configuration:

Let’s look at what i’ve found so far:
Going from the start of the file to the end
99 07 : This seems to be some sort of signature i have yet to find a flash drive that does not have it
10 : This is the vendor string length ( including zeroes , the length field itself and the type field )
26: This is the product string length ( including zeroes , the length field itself and the type field )
12 01 10 01 00 00 00 08: These bytes are still unknown , 12 could be the SCSI vendor string length , but still not tested
8F 05: This is the little endian representation of the VID ( Vendor ID ) that the usb device will show to the PC
87 63: This is the little endian representation of the PID ( Product ID ) that the usb device will show to the computer
05 01: These are the bcdDevice field of the usb descriptor
01:  Manufacter index ( not confirmed )
02: Product index , ( not confirmed )
00 01: Unknown
10: Again vendor string length
03: Descriptor type ( String)
10 03 48 00 61 00 63 00 6B 00 69 00 6E 00 67 00: Actual Vendor String
26: Product string length ( Again )
03: Descriptor type ( String )
50 00 52 00 4F 00 56 00 41 00 50 00 52 00 4F 00 44 00 4F 00 54 00 54 00 4F 00 50 00 52 00 4F 00 56 00 41 00: The actual product string
47 65 6E 65 72 69 63 20 46 6C 61 73 68 20 44 69 73 6B 20 20 20 20 20 20 38 2E 30 30: SCSI Identification string (Generic Flash Disk      8.00)
02: This byte is a checksum of the all bytes before it , if you set it incorrectly , the flash drive will refuse to use the settings, to calculate it , sum all bytes values ( unsigned ) , and then do &0xFF to use only the first eight bits.
AA 55 : Unknown 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 : Padding
3C C3 : Unknown
2A : Serial string length
03: Descriptor type (String )
32 00 30 00 31 00 34 00 30 00 37 00 31 00 39 00 31 00 34 00 31 00 34 00 32 00 37 00 30 00 38 00 35 00 46 00 30 00 37 00 42: The actual serial number string
After that there are @ offset 0xc3 an 0xc7 two 02 which are unknown
And @ 0xd4 there’s 88 50 51 49 which is unknown too
Once the settings have been uploaded , the flash drive has to be unplugged and plugged in again

The 0x82 command

This command instead, is used to read current configuration, it can be used in two ways

82 51 01 00 00 00 00 00 00 00

In that way you will get the current usb configuration with the same format as 0x81 command, 512 bytes too

82 51 00 00 00 00 00 00 00 00 

With this one instead you get another configuration(maybe) that still has to be investigated, and i have to figure out how it is uploaded too
I’ve created a git repository on containing the kernel patch and the current code for the alcorhack tool
Again , if someone wants to help, contact me on G+ or comment here 

Alcor UFD Controller Reverse engineering part 1 , querying info and decrypting the flash list shipped in AlcorMP tool

I’ve started that work because i want to port AlcorMP utility to Linux and to be able to use custom flash chips with these UFD chips, this utility called AlcorMP allows to do a lot of stuff , from checking flash integrity to programming the usb flash drive into a CD-Rom emulator.

For who is new to that field, these flash drives store configuration data and badblocks on an hidden sector of the flash memowy which normally is not visible by the end user.

To program that sector you have to issue vendor specific SCSI commands, the ones that i’ve found are:
0x9a: Seems to return 0x200 bytes of data still not reverse engineered
0xfa00: Seems to return 0x200 bytes of data too, but this one returns the Flash Chip identification as the first 6 bytes , so it’s something useful.
There’s also 0xf5 that is still unknown

Now the hard part, first thing you will see when you try to figure out where the program takes the flash and vendor, is that there’s no plaintext list with that data, and there’s no compressed data either.
Analyzing it with binwalk gives a very discouraging entropy graph as shown below entropy plot using binwalk -E

After some work on the UfdComLib.dll , it turns out that the file has been encrypted with a block cipher on purpose.

Lucky the program itself ( except LLF.dll that is encrypted too ), is not obfuscated , so it has been relatively easy extracting the encryption algorithm from the program and use it to decode the .

The function on UfdComLib.dll that gives an huge help locating the decryption code with IDA is the one at 0x100022F0

.text:100022F0 ; =============== S U B R O U T I N E =======================================
.text:100022F0 ; Attributes: bp-based frame
.text:100022F0 ; int __cdecl sub_100022F0(LPCSTR lpFileName)
.text:100022F0 sub_100022F0 proc near ; CODE XREF: sub_10001D80+292p
.text:100022F0 ReturnedString = byte ptr -14Ch
.text:100022F0 var_44 = byte ptr -44h
.text:100022F0 var_40 = byte ptr -40h
.text:100022F0 var_3C = byte ptr -3Ch
.text:100022F0 var_38 = byte ptr -38h
.text:100022F0 var_36 = byte ptr -36h
.text:100022F0 var_34 = byte ptr -34h
.text:100022F0 var_32 = byte ptr -32h
.text:100022F0 var_30 = byte ptr -30h
.text:100022F0 var_2E = byte ptr -2Eh
.text:100022F0 AppName = byte ptr -2Ch
.text:100022F0 var_24 = dword ptr -24h
.text:100022F0 var_20 = dword ptr -20h
.text:100022F0 var_1C = dword ptr -1Ch
.text:100022F0 var_18 = dword ptr -18h
.text:100022F0 var_14 = dword ptr -14h
.text:100022F0 var_10 = dword ptr -10h
.text:100022F0 var_C = dword ptr -0Ch
.text:100022F0 var_4 = dword ptr -4
.text:100022F0 hFile = dword ptr 8
.text:100022F0 push ebp
.text:100022F1 mov ebp, esp
.text:100022F3 push 0FFFFFFFFh
.text:100022F5 push offset SEH_100022F0
.text:100022FA mov eax, large fs:0
.text:10002300 push eax
.text:10002301 mov large fs:0, esp
.text:10002308 sub esp, 140h
.text:1000230E push ebx
.text:1000230F push esi
.text:10002310 push edi
.text:10002311 mov edi, [ebp+hFile]
.text:10002314 xor esi, esi
.text:10002316 mov [ebp+var_10], esp
.text:10002319 push esi ; hTemplateFile
.text:1000231A push 80h ; dwFlagsAndAttributes
.text:1000231F push 3 ; dwCreationDisposition
.text:10002321 push esi ; lpSecurityAttributes
.text:10002322 push 1 ; dwShareMode
.text:10002324 push 80000000h ; dwDesiredAccess
.text:10002329 push edi ; lpFileName
.text:1000232A mov [ebp+var_14], esi
.text:1000232D mov [ebp+var_4], esi
.text:10002330 call ds:CreateFileA
.text:10002336 cmp eax, 0FFFFFFFFh
.text:10002339 jz short loc_10002371
.text:1000233B push eax ; hObject
.text:1000233C call ds:CloseHandle
.text:10002342 push 4 ; int
.text:10002344 push edi ; lpFileName
.text:10002345 call sub_10004220
.text:1000234A mov ebx, eax
.text:1000234C add esp, 8
.text:1000234F cmp ebx, esi
.text:10002351 mov [ebp+var_24], ebx
.text:10002354 ja short loc_100023BD
.text:10002356 push offset aError_flash_it ; “ERROR_FLASH_ITEM_COUNT”
.text:1000235B lea ecx, [ebp+var_40]
.text:1000235E call ??0CString@@QAE@PBD@Z ; CString::CString(char const *)
.text:10002363 lea eax, [ebp+var_40]
.text:10002366 push offset unk_10006950
.text:1000236B push eax
.text:1000236C call _CxxThrowException
.text:10002371 ; —————————————————————————
.text:10002371 loc_10002371: ; CODE XREF: sub_100022F0+49j
.text:10002371 push offset asc_100081E4 ; “rn”
.text:10002376 lea ecx, [ebp+hFile]
.text:10002379 call ??0CString@@QAE@PBD@Z ; CString::CString(char const *)
.text:1000237E mov esi, eax
.text:10002380 push offset aError_file_no_ ; “ERROR_FILE_NO_EXISTS: ”
.text:10002385 lea ecx, [ebp+var_24]
.text:10002388 mov byte ptr [ebp+var_4], 1
.text:1000238C call ??0CString@@QAE@PBD@Z ; CString::CString(char const *)
.text:10002391 push edi
.text:10002392 push eax
.text:10002393 lea eax, [ebp+var_18]
.text:10002396 mov byte ptr [ebp+var_4], 2
.text:1000239A push eax
.text:1000239B call ??H@YG?AVCString@@ABV0@PBD@Z ; operator+(CString const &,char const *)
.text:100023A0 push esi
.text:100023A1 lea ecx, [ebp+var_3C]
.text:100023A4 push eax
.text:100023A5 push ecx
.text:100023A6 mov byte ptr [ebp+var_4], 3
.text:100023AA call ??H@YG?AVCString@@ABV0@0@Z ; operator+(CString const &,CString const &)
.text:100023AF lea edx, [ebp+var_3C]
.text:100023B2 push offset unk_10006950
.text:100023B7 push edx
.text:100023B8 call _CxxThrowException
.text:100023BD ; —————————————————————————
.text:100023BD loc_100023BD: ; CODE XREF: sub_100022F0+64j
.text:100023BD mov eax, ebx
.text:100023BF shl eax, 5
.text:100023C2 add eax, ebx
.text:100023C4 lea ecx, [eax+eax*4]
.text:100023C7 lea edx, [ebx+ecx*2]
.text:100023CA shl edx, 1
.text:100023CC push edx ; unsigned int
.text:100023CD call ??2@YAPAXI@Z ; operator new(uint)
.text:100023D2 add esp, 4
.text:100023D5 cmp eax, esi
.text:100023D7 mov [ebp+var_18], eax
.text:100023DA jz short loc_1000240A
.text:100023DC mov [ebp+var_14], ebx
.text:100023DF mov esi, 296h
.text:100023E4 mov edx, eax
.text:100023E6 loc_100023E6: ; CODE XREF: sub_100022F0+114j
.text:100023E6 mov ecx, [ebp+var_14]
.text:100023E9 dec ecx
.text:100023EA mov [ebp+var_14], ecx
.text:100023ED js short loc_10002406
.text:100023EF mov ecx, 0A5h
.text:100023F4 xor eax, eax
.text:100023F6 mov edi, edx
.text:100023F8 add edx, esi
.text:100023FA rep stosd
.text:100023FC stosw
.text:100023FE mov edi, [ebp+hFile]
.text:10002401 mov eax, [ebp+var_18]
.text:10002404 jmp short loc_100023E6
.text:10002406 ; —————————————————————————
.text:10002406 loc_10002406: ; CODE XREF: sub_100022F0+FDj
.text:10002406 xor esi, esi
.text:10002408 jmp short loc_1000240C
.text:1000240A ; —————————————————————————
.text:1000240A loc_1000240A: ; CODE XREF: sub_100022F0+EAj
.text:1000240A xor eax, eax
.text:1000240C loc_1000240C: ; CODE XREF: sub_100022F0+118j
.text:1000240C push ebx ; int
.text:1000240D push esi ; int
.text:1000240E push eax ; int
.text:1000240F push 4 ; int
.text:10002411 push edi ; hFile
.text:10002412 mov [ebp+var_14], eax
.text:10002415 call sub_100043D0
.text:1000241A add esp, 14h
.text:1000241D cmp eax, esi
.text:1000241F jnz short loc_1000243C
.text:10002421 push offset aError_flashlis ; “ERROR_FlashListApi_ReadItemrn”
.text:10002426 lea ecx, [ebp+var_44]
.text:10002429 call ??0CString@@QAE@PBD@Z ; CString::CString(char const *)
.text:1000242E lea eax, [ebp+var_44]
.text:10002431 push offset unk_10006950
.text:10002436 push eax
.text:10002437 call _CxxThrowException
.text:1000243C ; —————————————————————————
.text:1000243C loc_1000243C: ; CODE XREF: sub_100022F0+12Fj
.text:1000243C push 0FFFFFFFFh
.text:1000243E push esi
.text:1000243F mov ecx, offset unk_10008430
.text:10002444 call sub_10003060
.text:10002449 cmp ebx, esi
.text:1000244B jnz short loc_1000249E
.text:1000244D mov edi, dword_10008434
.text:10002453 cmp edi, esi
.text:10002455 jz short loc_1000248D
.text:10002457 mov esi, dword_10008438
.text:1000245D loc_1000245D: ; CODE XREF: sub_100022F0+180j
.text:1000245D mov ecx, esi
.text:1000245F dec esi
.text:10002460 test ecx, ecx
.text:10002462 jz short loc_10002472
.text:10002464 push 0 ; char
.text:10002466 mov ecx, edi ; void *
.text:10002468 call sub_100040E0
.text:1000246D add edi, 10h
.text:10002470 jmp short loc_1000245D
.text:10002472 ; —————————————————————————
.text:10002472 loc_10002472: ; CODE XREF: sub_100022F0+172j
.text:10002472 mov edx, dword_10008434
.text:10002478 push edx ; void *
.text:10002479 call ??3@YAXPAX@Z ; operator delete(void *)
.text:1000247E add esp, 4
.text:10002481 mov dword_10008434, 0
.text:1000248B xor esi, esi
.text:1000248D loc_1000248D: ; CODE XREF: sub_100022F0+165j
.text:1000248D mov dword_1000843C, esi
.text:10002493 mov dword_10008438, esi
.text:10002499 jmp loc_100025C7
.text:1000249E ; —————————————————————————
.text:1000249E loc_1000249E: ; CODE XREF: sub_100022F0+15Bj
.text:1000249E mov edx, dword_10008434
.text:100024A4 cmp edx, esi
.text:100024A6 jnz short loc_100024D3
.text:100024A8 mov eax, ebx
.text:100024AA shl eax, 4
.text:100024AD push eax ; unsigned int
.text:100024AE call ??2@YAPAXI@Z ; operator new(uint)
.text:100024B3 add esp, 4
.text:100024B6 mov dword_10008434, eax
.text:100024BB push ebx
.text:100024BC push eax
.text:100024BD call sub_10003DF0
.text:100024C2 mov dword_1000843C, ebx
.text:100024C8 loc_100024C8: ; CODE XREF: sub_100022F0:loc_10002501j
.text:100024C8 ; sub_100022F0+223j
.text:100024C8 mov dword_10008438, ebx
.text:100024CE jmp loc_100025C7
.text:100024D3 ; —————————————————————————
.text:100024D3 loc_100024D3: ; CODE XREF: sub_100022F0+1B6j
.text:100024D3 mov ecx, dword_1000843C
.text:100024D9 cmp ebx, ecx
.text:100024DB jg short loc_10002523
.text:100024DD mov eax, dword_10008438
.text:100024E2 cmp eax, ebx
.text:100024E4 jge short loc_10002501
.text:100024E6 mov ecx, ebx
.text:100024E8 sub ecx, eax
.text:100024EA shl eax, 4
.text:100024ED add eax, edx
.text:100024EF push ecx
.text:100024F0 push eax
.text:100024F1 call sub_10003DF0
.text:100024F6 mov dword_10008438, ebx
.text:100024FC jmp loc_100025C7

This function uses another function to read the header and get the number of entries on the flash list file , sub_10004220

.text:10004220 ; =============== S U B R O U T I N E =======================================
.text:10004220 ; int __cdecl sub_10004220(LPCSTR lpFileName, int)
.text:10004220 sub_10004220 proc near ; CODE XREF: sub_100022F0+55p
.text:10004220 var_100 = dword ptr -100h
.text:10004220 var_DC = dword ptr -0DCh
.text:10004220 var_D4 = dword ptr -0D4h
.text:10004220 lpFileName = dword ptr 4
.text:10004220 arg_4 = dword ptr 8
.text:10004220 mov ecx, [esp+lpFileName]
.text:10004224 sub esp, 100h
.text:1000422A lea eax, [esp+100h+var_100]
.text:1000422E push esi
.text:1000422F push eax ; int
.text:10004230 push ecx ; lpFileName
.text:10004231 xor esi, esi
.text:10004233 call sub_10004270
.text:10004238 add esp, 8
.text:1000423B test eax, eax
.text:1000423D jnz short loc_10004247
.text:1000423F pop esi
.text:10004240 add esp, 100h
.text:10004246 retn
.text:10004247 ; —————————————————————————
.text:10004247 loc_10004247: ; CODE XREF: sub_10004220+1Dj
.text:10004247 mov edx, [esp+104h+var_DC]

This one above checks if the file has been read successfully and if yes, it returns the number of entries of the flash list file.
.text:10004270 ; =============== S U B R O U T I N E =======================================
.text:10004270 ; Attributes: bp-based frame
.text:10004270 ; int __cdecl sub_10004270(LPCSTR lpFileName, int)
.text:10004270 sub_10004270 proc near ; CODE XREF: sub_10004220+13p
.text:10004270 Buffer = byte ptr -328h
.text:10004270 var_228 = byte ptr -228h
.text:10004270 var_128 = byte ptr -128h
.text:10004270 dwErrCode = dword ptr -28h
.text:10004270 NumberOfBytesRead= dword ptr -24h
.text:10004270 var_20 = dword ptr -20h
.text:10004270 var_1C = dword ptr -1Ch
.text:10004270 var_18 = dword ptr -18h
.text:10004270 var_14 = dword ptr -14h
.text:10004270 var_10 = dword ptr -10h
.text:10004270 var_C = dword ptr -0Ch
.text:10004270 var_4 = dword ptr -4
.text:10004270 lpFileName = dword ptr 8
.text:10004270 arg_4 = dword ptr 0Ch
.text:10004270 push ebp
.text:10004271 mov ebp, esp
.text:10004273 push 0FFFFFFFFh
.text:10004275 push offset SEH_10004270
.text:1000427A mov eax, large fs:0
.text:10004280 push eax
.text:10004281 mov large fs:0, esp
.text:10004288 sub esp, 31Ch
.text:1000428E push ebx
.text:1000428F push esi
.text:10004290 mov eax, [ebp+lpFileName]
.text:10004293 push edi
.text:10004294 xor esi, esi
.text:10004296 mov [ebp+var_10], esp
.text:10004299 push esi ; hTemplateFile
.text:1000429A push 80h ; dwFlagsAndAttributes
.text:1000429F mov edi, 1
.text:100042A4 push 3 ; dwCreationDisposition
.text:100042A6 push esi ; lpSecurityAttributes
.text:100042A7 push edi ; dwShareMode
.text:100042A8 push 80000000h ; dwDesiredAccess
.text:100042AD push eax ; lpFileName
.text:100042AE mov [ebp+var_14], edi
.text:100042B1 mov [ebp+var_4], esi
.text:100042B4 call ds:CreateFileA
.text:100042BA mov ebx, eax
.text:100042BC cmp ebx, 0FFFFFFFFh
.text:100042BF mov [ebp+lpFileName], ebx
.text:100042C2 jnz short loc_100042D5
.text:100042C4 lea ecx, [ebp+var_20]
.text:100042C7 push offset unk_100069F0
.text:100042CC push ecx
.text:100042CD mov [ebp+var_20], esi
.text:100042D0 call _CxxThrowException
.text:100042D5 ; —————————————————————————
.text:100042D5 loc_100042D5: ; CODE XREF: sub_10004270+52j
.text:100042D5 lea edx, [ebp+NumberOfBytesRead]
.text:100042D8 push esi ; lpOverlapped
.text:100042D9 push edx ; lpNumberOfBytesRead
.text:100042DA lea eax, [ebp+Buffer]
.text:100042E0 push 200h ; nNumberOfBytesToRead
.text:100042E5 push eax ; lpBuffer
.text:100042E6 push ebx ; hFile
.text:100042E7 call ds:ReadFile
.text:100042ED cmp [ebp+NumberOfBytesRead], 200h
.text:100042F4 jz short loc_10004307
.text:100042F6 lea ecx, [ebp+var_18]
.text:100042F9 push offset unk_100069F0
.text:100042FE push ecx
.text:100042FF mov [ebp+var_18], edi
.text:10004302 call _CxxThrowException
.text:10004307 ; —————————————————————————
.text:10004307 loc_10004307: ; CODE XREF: sub_10004270+84j
.text:10004307 lea edx, [ebp+var_128]
.text:1000430D lea eax, [ebp+Buffer]
.text:10004313 push edx
.text:10004314 push 10h
.text:10004316 push offset unk_10006840
.text:1000431B push 100h
.text:10004320 push eax
.text:10004321 call sub_10004650
.text:10004326 mov esi, [ebp+arg_4]
.text:10004329 add esp, 14h
.text:1000432C lea ecx, [ebp+var_128]
.text:10004332 lea edx, [ebp+var_228]
.text:10004338 push esi
.text:10004339 push 100h
.text:1000433E push ecx
.text:1000433F push 100h
.text:10004344 push edx
.text:10004345 call sub_10004650
.text:1000434A add esp, 14h
.text:1000434D mov ecx, 4
.text:10004352 mov edi, offset unk_10006840
.text:10004357 xor eax, eax
.text:10004359 repe cmpsd
.text:1000435B jz short loc_100043A4
.text:1000435D lea ecx, [ebp+var_1C]
.text:10004360 push offset unk_100069F0
.text:10004365 push ecx
.text:10004366 mov [ebp+var_1C], 2
.text:1000436D call _CxxThrowException
.text:10004372 ; —————————————————————————
.text:10004372 loc_10004372: ; DATA XREF: .rdata:stru_10006E88o
.text:10004372 mov edx, [ebp+dwErrCode]
.text:10004375 mov [ebp+var_14], 0
.text:1000437C push edx ; dwErrCode
.text:1000437D call ds:SetLastError
.text:10004383 mov eax, offset loc_100043A1
.text:10004388 retn
.text:10004389 ; —————————————————————————
.text:10004389 loc_10004389: ; DATA XREF: .rdata:stru_10006E88o
.text:10004389 push 0FFh ; dwErrCode
.text:1000438E mov [ebp+var_14], 0
.text:10004395 call ds:SetLastError
.text:1000439B mov eax, offset loc_100043A1
.text:100043A0 retn
.text:100043A1 ; —————————————————————————
.text:100043A1 loc_100043A1: ; DATA XREF: sub_10004270+113o
.text:100043A1 ; sub_10004270+12Bo
.text:100043A1 mov ebx, [ebp+lpFileName]
.text:100043A4 loc_100043A4: ; CODE XREF: sub_10004270+EBj
.text:100043A4 cmp ebx, 0FFFFFFFFh
.text:100043A7 jz short loc_100043B0
.text:100043A9 push ebx ; hObject
.text:100043AA call ds:CloseHandle
.text:100043B0 loc_100043B0: ; CODE XREF: sub_10004270+137j
.text:100043B0 mov ecx, [ebp+var_C]
.text:100043B3 mov eax, [ebp+var_14]
.text:100043B6 pop edi
.text:100043B7 pop esi
.text:100043B8 mov large fs:0, ecx
.text:100043BF pop ebx
.text:100043C0 mov esp, ebp
.text:100043C2 pop ebp
.text:100043C3 retn
.text:100043C3 sub_10004270 endp ; sp-analysis failed
.text:100043C3 ; —————————————————————————
sub_10004270 is interesting, it actually opens the file and reads a 512 byte block, then a function is used multiple times on the data read from the file: sub_10004650
sub_10004650 is just a wrapper around sub_10004680 , and it does only dereference some char ** to char* , so let’s checkout sub_10004680
.text:10004680 ; =============== S U B R O U T I N E =======================================
.text:10004680 ; int __cdecl sub_10004680(char *, int, char *, int, char *)
.text:10004680 sub_10004680 proc near ; CODE XREF: sub_10004650+19p
.text:10004680 arg_0 = dword ptr 4
.text:10004680 arg_4 = dword ptr 8
.text:10004680 arg_8 = dword ptr 0Ch
.text:10004680 arg_C = dword ptr 10h
.text:10004680 arg_10 = dword ptr 14h
.text:10004680 push ebx
.text:10004681 push ebp
.text:10004682 mov ebp, [esp+8+arg_0]
.text:10004686 push edi
.text:10004687 test ebp, ebp
.text:10004689 jz loc_10004750
.text:1000468F mov ebx, [esp+0Ch+arg_8]
.text:10004693 test ebx, ebx
.text:10004695 jz loc_10004750
.text:1000469B mov edi, [esp+0Ch+arg_10]
.text:1000469F test edi, edi
.text:100046A1 jz loc_10004750
.text:100046A7 push esi
.text:100046A8 push 100h ; unsigned int
.text:100046AD call ??2@YAPAXI@Z ; operator new(uint)
.text:100046B2 mov esi, eax
.text:100046B4 mov eax, [esp+14h+arg_C]
.text:100046B8 push esi
.text:100046B9 push eax
.text:100046BA push ebx
.text:100046BB call sub_10004760
.text:100046C0 mov edx, [esp+20h+arg_4]
.text:100046C4 add esp, 10h
.text:100046C7 xor eax, eax
.text:100046C9 xor ecx, ecx
.text:100046CB test edx, edx
.text:100046CD jbe short loc_10004740
.text:100046CF sub ebp, edi
.text:100046D1 mov [esp+10h+arg_0], edx
.text:100046D5 loc_100046D5: ; CODE XREF: sub_10004680+BAj
.text:100046D5 inc eax
.text:100046D6 and eax, 0FFh
.text:100046DB mov dl, [eax+esi]
.text:100046DE mov bl, [eax+esi]
.text:100046E1 add edx, ecx
.text:100046E3 and edx, 0FFh
.text:100046E9 mov ecx, edx
.text:100046EB mov dl, [ecx+esi]
.text:100046EE xor bl, dl
.text:100046F0 mov [eax+esi], bl
.text:100046F3 mov dl, bl
.text:100046F5 mov bl, [ecx+esi]
.text:100046F8 xor bl, dl
.text:100046FA mov [ecx+esi], bl
.text:100046FD mov dl, bl
.text:100046FF mov bl, [eax+esi]
.text:10004702 xor bl, dl
.text:10004704 mov [eax+esi], bl
.text:10004707 mov dl, bl
.text:10004709 xor ebx, ebx
.text:1000470B and edx, 0FFh
.text:10004711 mov bl, [ecx+esi]
.text:10004714 add edx, ebx
.text:10004716 and edx, 800000FFh
.text:1000471C jns short loc_10004726
.text:1000471E dec edx
.text:1000471F or edx, 0FFFFFF00h
.text:10004725 inc edx
.text:10004726 loc_10004726: ; CODE XREF: sub_10004680+9Cj
.text:10004726 mov dl, [edx+esi]
.text:10004729 mov bl, [edi+ebp]
.text:1000472C xor dl, bl
.text:1000472E mov [edi], dl
.text:10004730 mov edx, [esp+10h+arg_0]
.text:10004734 inc edi
.text:10004735 dec edx
.text:10004736 mov [esp+10h+arg_0], edx
.text:1000473A jnz short loc_100046D5
.text:1000473C mov edi, [esp+10h+arg_10]
.text:10004740 loc_10004740: ; CODE XREF: sub_10004680+4Dj
.text:10004740 push esi ; void *
.text:10004741 call ??3@YAXPAX@Z ; operator delete(void *)
.text:10004746 add esp, 4
.text:10004749 mov eax, edi
.text:1000474B pop esi
.text:1000474C pop edi
.text:1000474D pop ebp
.text:1000474E pop ebx
.text:1000474F retn
.text:10004750 ; —————————————————————————
.text:10004750 loc_10004750: ; CODE XREF: sub_10004680+9j
.text:10004750 ; sub_10004680+15j …
.text:10004750 pop edi
.text:10004751 pop ebp
.text:10004752 xor eax, eax
.text:10004754 pop ebx
.text:10004755 retn
.text:10004755 sub_10004680 endp
.text:10004755 ; —————————————————————————

This one is clearly an encryption algorithm, but before having a complete view on the problem there’s also another function: sub_10004760

.text:10004760 ; =============== S U B R O U T I N E =======================================
.text:10004760 sub_10004760 proc near ; CODE XREF: sub_10004680+3Bp
.text:10004760 arg_0 = dword ptr 4
.text:10004760 arg_4 = dword ptr 8
.text:10004760 arg_8 = dword ptr 0Ch
.text:10004760 push ebx
.text:10004761 mov ebx, [esp+4+arg_0]
.text:10004765 test ebx, ebx
.text:10004767 jz short loc_100047CC
.text:10004769 mov ecx, [esp+4+arg_8]
.text:1000476D test ecx, ecx
.text:1000476F jz short loc_100047CC
.text:10004771 push ebp
.text:10004772 push esi
.text:10004773 push edi
.text:10004774 xor edi, edi
.text:10004776 xor eax, eax
.text:10004778 loc_10004778: ; CODE XREF: sub_10004760+21j
.text:10004778 mov [eax+ecx], al
.text:1000477B inc eax
.text:1000477C cmp eax, 100h
.text:10004781 jb short loc_10004778
.text:10004783 mov ebp, [esp+10h+arg_4]
.text:10004787 xor esi, esi
.text:10004789 loc_10004789: ; CODE XREF: sub_10004760+63j
.text:10004789 mov eax, esi
.text:1000478B xor edx, edx
.text:1000478D div ebp
.text:1000478F mov al, [edx+ebx]
.text:10004792 mov dl, [esi+ecx]
.text:10004795 add edi, edx
.text:10004797 add eax, edi
.text:10004799 and eax, 0FFh
.text:1000479E mov edi, eax
.text:100047A0 mov al, [edi+ecx]
.text:100047A3 xor dl, al
.text:100047A5 mov [esi+ecx], dl
.text:100047A8 mov al, dl
.text:100047AA mov dl, [edi+ecx]
.text:100047AD xor dl, al
.text:100047AF mov [edi+ecx], dl
.text:100047B2 mov al, dl
.text:100047B4 mov dl, [esi+ecx]
.text:100047B7 xor dl, al
.text:100047B9 mov [esi+ecx], dl
.text:100047BC inc esi
.text:100047BD cmp esi, 100h
.text:100047C3 jb short loc_10004789
.text:100047C5 pop edi
.text:100047C6 pop esi
.text:100047C7 pop ebp
.text:100047C8 mov eax, ecx
.text:100047CA pop ebx
.text:100047CB retn
After studying on it some hours i’ve figured out that sub_10004760 is a function used to inizialize a vector of length 256 ( 0x100 ) with the encryption key that is later used on the caller function.
With HexRays decompiler it’s fairly easy to generate proper C code of these functions and so re-use them.
The file is made of a first 256 byte block , that encrypted using the algorithm above and “ALCORFLASHCFG_SZ” as the key yields other 256 bytes that have to be used as the key for the next 256 byte block inside the file that is the header.
The header contains some useful info like the size of each record , the number of records and what i think to be the version ( 4 ) as follows:

The data after the header is organized in entry_size sized blocks and each one is decrypted using the same key obtained to decrypt the header, but , the first keybyte has to be the record number starting from 0 and the last keybyte has to be the bitwise negation of the record number
This gives us records on which i’m still working to figure out the exact format , but what i’ve defined so far:

Other fields still have to be reverse engineered, and they are mandatory to be able to write a program that can reprogram these flash drives.
The complete program that can read the flash list is the following:

If someone is interested in helping me on that work , comment here, or circle me on Google Plus

Resurrecting QBell 39″ LCD LED TV as VGA display using an MT6820 board

I’ve got that TV to be trashed, because after some hours it won’t turn on anymore, first thing i’ve checked is the power supply which was fine.
The original board is labeled “T.MSD309.B21B”, and apparently it is a chinese universal LVDS LCD driver board.

So i’ve checked on ebay and that board is available , but it costs a lot of money ( 80+ € excl. shipping ) , and since the old one broke almost in new condition, and i’m pretty sure it is software-broken, it’s reasonable to think that the board is flawed and it will break again and again.
Also i couldn’t be sure that the panel was in working condition , so 100 € is too much risky considering that and what said above.

I’ve choosen then, to use an MT6820 board which can be bought from ebay for as low as 6€, it has only VGA input , but it is fine for what i want to use that LCD for.

This board has various options to support most LCD panels, so i’ve tried all of them, and the one that is closest to perfection is the no. 1.
But it isn’t perfect, you will get swapped columns.
While going through various LVDS pinouts i’ve noticed that a group of signals is marked “EVEN” and another group “ODD”, since the number of pixels horizontally is even, it clearly appears to be caused by swapped EVEN and ODD connections.

The glitch caused by swapped EVEN and ODD

When swapping the signals according to the MT6820 pinout, i was very tired and screwed up all the ordering , so i had to find again the correct pinout.
Since the Part.NO of the panel gives 0 results on google , literally, i’ve spotted the lvds controller board chip manufacter on the panel , which is “CMO” , CMO stands for ChiMei Optoelectronics, but it does not longer exist , however , after some more hard search , i’ve figured out that it has been acquired by Innolux, and then i’ve picked the first datasheet of a LED backlit panel 39 inches wide.

After having the right pinout i’ve reassembled the cable and i’ve got to the starting point where columns were swapped.

So the next day, after some rest , i’ve tried again to swap the connections , and it finally works.

Now let get deeper into the details, if you order an MT6820 , you will likely get an LVDS cable that is useless for our work, and a button board that we need instead.

The button board must be connected with the supplied cable even if the pin count does not match, that is because K5 and K6 on the input side are unused.
Make sure that the other input pins and led pins match on the button board.

On the QBell LVDS cable you have to swap all the EVEN pins with ODD pins, to do that , do not cut the wires or do some s**t like that , instead just use some thin object like a needle to extract the contacts from the plastic of the connector on the MT6820 side and swap them all.

Now that you have ( hopefully ) correct LVDS connection, you need to do one more thing , the MT6820 supports only 3.3V and 5V panel , instead at least on this QBell , the panel voltage is 12V , so you have to cut the Red wires ( pins 1,2,3 ) and connect them with the +12V from the power supply( you can see output voltages from the PCB of the power supply , since they are labeled ).

The backlight is not electrically compatible with the MT6820 so you have to just connect both BLON and ADJ pins of the power supply to +5VSB .
The +5V of the MT6820 instead has to be connected on the +5V of the power supply.
To make the power supply power on as soon you plug the TV to the outlet, connect PSON and +5VSB together.

The MT6820 board “installed”

If nothing is wrong you should see “No signal” written in chinese and it should work correctly as a regular PC VGA display.

LCD Panel pinout

LCD Panel pinout
MT6820 pinout