| 
		 After Width: | Height: | Size: 588 KiB  | 
| 
		 After Width: | Height: | Size: 207 KiB  | 
| 
		 After Width: | Height: | Size: 565 KiB  | 
| 
		 After Width: | Height: | Size: 116 KiB  | 
| 
		 After Width: | Height: | Size: 163 KiB  | 
| 
		 After Width: | Height: | Size: 109 KiB  | 
| 
		 After Width: | Height: | Size: 117 KiB  | 
| 
		 After Width: | Height: | Size: 115 KiB  | 
| 
		 After Width: | Height: | Size: 108 KiB  | 
| 
		 After Width: | Height: | Size: 112 KiB  | 
| 
		 After Width: | Height: | Size: 107 KiB  | 
| 
		 After Width: | Height: | Size: 114 KiB  | 
| 
		 After Width: | Height: | Size: 425 KiB  | 
@@ -0,0 +1,164 @@
 | 
			
		||||
+++
 | 
			
		||||
title = "Reverse engineering di un lettore di presenze"
 | 
			
		||||
summary = "Step 1: incominciare a capire come funziona il tutto"
 | 
			
		||||
date = "2024-04-28"
 | 
			
		||||
 | 
			
		||||
tags = ["Reverse Engineering", "Lettore di Presenze", "Decompilazione", "Codemerx"]
 | 
			
		||||
categories = ["Progetti"]
 | 
			
		||||
series = ["Lettore di presenze"]
 | 
			
		||||
series_order = 1
 | 
			
		||||
+++
 | 
			
		||||
 | 
			
		||||
Uno dei motivi per cui ho creato questo blog è per condividere le mie
 | 
			
		||||
esperienze con altri pazzi entusiasti che adorano questo tipo di contenuti di
 | 
			
		||||
nicchia come me.
 | 
			
		||||
 | 
			
		||||
In questa serie di articoli andrò a spiegare come ho eseguito il reverse
 | 
			
		||||
engineering del protocollo di comunicazione usato tra un lettore di presenze ed
 | 
			
		||||
il suo client (ovviamente creato solo per Windows) ed andremo a creare un
 | 
			
		||||
client alternativo con [Rust](https://rust-lang.org/) e
 | 
			
		||||
[Tauri](https://tauri.app/) per rimpiazzare quello proprietario.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Un po' di background
 | 
			
		||||
 | 
			
		||||
Mio padre ha voluto aggiornare il vecchio lettore di presenze per la sua
 | 
			
		||||
attività: è volato su Amazon e ha comprato
 | 
			
		||||
l'[R701](https://ipsattendant.it/rilevatore-presenze-r701/) di [I.P.S.
 | 
			
		||||
Informatica](https://ipsinformatica.info/).
 | 
			
		||||
 | 
			
		||||
A differenza del vecchio lettore, con questo i dipendenti possono registrare la
 | 
			
		||||
loro presenza tramite PIN, impronta digitale o tramite un badge RFID, poi le
 | 
			
		||||
registrazioni possono essere scaricate tramite il client ufficiale per Windows
 | 
			
		||||
o tramite una chiavetta USB.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Il problema è che il client, oltre ad essere installabile solo su Windows e
 | 
			
		||||
richiedere un'account per eseguire azioni offline, non risponde ai requisiti
 | 
			
		||||
dell'azienda.
 | 
			
		||||
 | 
			
		||||
Sarebbe gradito che ogni mese venisse fatto un report per ogni dipendente, con
 | 
			
		||||
una tabella che permetta di vedere le ore lavorate ogni giorno. Invece il
 | 
			
		||||
software ufficiale permette di scaricare solo una lista di presenze, senza
 | 
			
		||||
alcun tipo di divisione per mese o per dipendente, e non permette di esportare
 | 
			
		||||
il tutto in un file `.ods`.
 | 
			
		||||
 | 
			
		||||
Così, in pura modalità "[Stallman quando la nuova stampante Xerox si
 | 
			
		||||
inceppa](https://oreilly.com/openbook/freedom/ch01.html)", ho deciso che la
 | 
			
		||||
soluzione migliore è riscrivere il tutto in modo *open-source*.
 | 
			
		||||
 | 
			
		||||
## Dump delle registrazioni tramite USB
 | 
			
		||||
 | 
			
		||||
Come prima cosa ho provato a scaricare le registrazioni tramite una chiavetta
 | 
			
		||||
USB, dato che questo metodo non necessita di un PC Windows. Così ho formattato
 | 
			
		||||
una chiavetta in FAT32 e, dopo aver creato un utente di test e aver creato
 | 
			
		||||
qualche registrazione, ho scaricato i dati sul mio laptop.
 | 
			
		||||
 | 
			
		||||
Una volta aperto il contenuto della chiavetta ho notato che il lettore ha
 | 
			
		||||
creato due file:
 | 
			
		||||
 | 
			
		||||
* `~tmp.tmp`: che contiene la stringa `usb test!!` ripetuta 384 volte;
 | 
			
		||||
* `AGLog_001.txt`: che contiene le registrazioni.
 | 
			
		||||
 | 
			
		||||
Credo che il file `~tmp.tmp` venga usato dal registratore solo per vedere se la
 | 
			
		||||
chiavetta USB è scrivibile, quindi possoiamo ignorarlo.
 | 
			
		||||
 | 
			
		||||
Aprendo il file `AGLog_001.txt` possiamo andare ad intuire i vari campi che il
 | 
			
		||||
lettore si salva in memoria:
 | 
			
		||||
 | 
			
		||||
```csv
 | 
			
		||||
No	Mchn	EnNo		Name		Mode	IOMd	DateTime	
 | 
			
		||||
000001	1	000000001	test      	34	0	2024/04/28  16:04:23
 | 
			
		||||
000002	1	000000001	test      	33	1	2024/04/28  16:05:28
 | 
			
		||||
000003	1	000000001	test      	35	2	2024/04/28  16:08:49
 | 
			
		||||
000004	1	000000001	test     	35	3	2024/04/28  16:09:01
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `No` è l'ID della registrazione
 | 
			
		||||
* `Mchn` è l'ID del registratore
 | 
			
		||||
* `EnNo` è l'ID del dipendente che ha effettuato la registrazione
 | 
			
		||||
  (**En**ployee**No**mber ?)
 | 
			
		||||
* `Name` è il nome del dipendente
 | 
			
		||||
* `Mode` è la modalità con coi il dipendente ha registrato la presenza:
 | 
			
		||||
  * `33` è tramite l'impronta digitale
 | 
			
		||||
  * `34` è usando il PIN
 | 
			
		||||
  * `35` è con il badge
 | 
			
		||||
* `IOMd` è il campo che simboleggia l'ingresso o l'uscita del dipendente
 | 
			
		||||
  (**I**n/**O**ut **M**o**d**e ?):
 | 
			
		||||
  * `0` è il primo ingresso
 | 
			
		||||
  * `1` è la prima uscita
 | 
			
		||||
  * `2` è il secondo ingresso
 | 
			
		||||
  * `3` è la seconda uscita
 | 
			
		||||
* `Datetime` è la data e l'ora della registrazione
 | 
			
		||||
 | 
			
		||||
Considerando che ho registrato le presenze passando per tutte le modalità di
 | 
			
		||||
ingresso e di uscita in ordine e che ho usato il PIN la prima volta, l'impronta
 | 
			
		||||
digitale la seconda ed il badge le ultime due, possiamo ritenerci soddisfatti
 | 
			
		||||
del risultato.
 | 
			
		||||
 | 
			
		||||
Potremmo addirittura scrivere un programma in Python che usi la libreria
 | 
			
		||||
[csv](https://docs.python.org/3/library/csv.html) per estrarre i dati che ci
 | 
			
		||||
servono da questo file.
 | 
			
		||||
 | 
			
		||||
Ma questo non sarebbe così interessante da essere un post sul mio blog. Non
 | 
			
		||||
voglio entrare nel menù di amministrazione del dispositivo per poi premere in
 | 
			
		||||
ordine i tasti `2`, `1` e `2` per fare il dump, poi prendere il file risultante
 | 
			
		||||
e filtrarlo con uno script Python senza interfaccia grafica.
 | 
			
		||||
 | 
			
		||||
Voglio creare un programma che funzioni nativamente su Windows e Linux e che mi
 | 
			
		||||
permetta di scaricare tutti i dati che mi interessano con un singolo click, già
 | 
			
		||||
formattati correttamente.
 | 
			
		||||
 | 
			
		||||
Prima di tirare fuori [Wireshark](https://wireshark.org/) e provare a sniffare
 | 
			
		||||
dei pacchetti però, voglio provare un'altra tecnica...
 | 
			
		||||
 | 
			
		||||
## Decompilare il client closed-source
 | 
			
		||||
 | 
			
		||||
Come disse una volta [un
 | 
			
		||||
saggio](https://twitter.com/DebugPrivilege/status/1531661046238388226): "Tutto
 | 
			
		||||
il codice è *open-source* se sai leggere Assembly".
 | 
			
		||||
 | 
			
		||||
Dato che la compagnia che ha scritto il codice è italiana e che il client
 | 
			
		||||
funziona solo su Windows, c'è un alta probabilità che il codice sia stato
 | 
			
		||||
scritto in C# su piattaforma .NET.
 | 
			
		||||
 | 
			
		||||
Se questo è il caso, dovrebbe essere abbastanza semplice ottenere il codice
 | 
			
		||||
sorgente tramite un decompilatore come
 | 
			
		||||
[CodemerxDecompile](https://decompiler.codemerx.com/).
 | 
			
		||||
 | 
			
		||||
Quindi ho creato una macchina virtuale con [Windows 10
 | 
			
		||||
AME](https://archive.org/details/windows10-ame-21h1-2021-08-09/) e ho
 | 
			
		||||
installato il client ufficiale alla [versione
 | 
			
		||||
04.03.02](https://ipsattendant.it/download-programmi-e-manuali/).
 | 
			
		||||
 | 
			
		||||
{{< carousel images="images/03-official-client-installation/*"
 | 
			
		||||
aspectRatio="16-9" interval="1000" >}}
 | 
			
		||||
 | 
			
		||||
Una volta installato il client ufficiale ho copiato la directory `C:\Program
 | 
			
		||||
Files (x86)\ipsAttendant` sulla mia macchina Linux e l'ho aperta con
 | 
			
		||||
CodemerxDecompile.
 | 
			
		||||
 | 
			
		||||
Come avevo previsto il codice è scritto in C#, quindi è facilmente leggibile.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Cercando di qua e di là ho scoperto l'amara verità: dentro al file
 | 
			
		||||
`Dichiarazioni.cs` sono presenti molti metodi interessanti, come
 | 
			
		||||
`FK_ConnectNet()`. Questi metodi però sono tutti import da una libreria
 | 
			
		||||
chiamata `FKAttend.dll`.
 | 
			
		||||
 | 
			
		||||
Cercando sul web, sembra che questa libreria sia in giro da molti anni e dubito
 | 
			
		||||
altamente che l'abbia scritta la compagnia del lettore. Ho trovato anche [la
 | 
			
		||||
documentazione ufficiale del
 | 
			
		||||
DDL](</posts/2024/04/reverse-engineering-an-attendance-clock-part-1/FKAttend User's Manual.pdf>),
 | 
			
		||||
ma nient'altro.
 | 
			
		||||
 | 
			
		||||
Dato che decompilare una libreria che manco il creatore ha avuto voglia di
 | 
			
		||||
implementare da se non è una cosa che sono disposto a fare, nel prossimo
 | 
			
		||||
articolo proveremo a fare il reverse engineering della comunicazione che
 | 
			
		||||
avviene tra client e dispositivo.
 | 
			
		||||
@@ -0,0 +1,158 @@
 | 
			
		||||
+++
 | 
			
		||||
title = "Reverse Engineering of an Attendance Reader"
 | 
			
		||||
summary = "Step 1: Beginning to understand how everything works"
 | 
			
		||||
date = "2024-04-28"
 | 
			
		||||
 | 
			
		||||
tags = ["Reverse Engineering", "Attendance Reader", "Decompilation", "Codemerx"]
 | 
			
		||||
categories = ["Projects"]
 | 
			
		||||
series = ["Attendance Reader"]
 | 
			
		||||
series_order = 1
 | 
			
		||||
+++
 | 
			
		||||
 | 
			
		||||
One of the reasons I created this blog is to share my experiences with other
 | 
			
		||||
enthusiastic geeks who love this kind of niche content like me.
 | 
			
		||||
 | 
			
		||||
In this series of articles, I will explain to you how I reverse-engineered the
 | 
			
		||||
communication protocol used between an attendance reader and its (Windows-only)
 | 
			
		||||
client, and we will create an alternative client with
 | 
			
		||||
[Rust](https://rust-lang.org/) and [Tauri](https://tauri.app/) to replace the
 | 
			
		||||
proprietary one.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## A bit of background
 | 
			
		||||
 | 
			
		||||
My dad wanted to update the old attendance reader for his small business, so he
 | 
			
		||||
went straight on Amazon and bought the
 | 
			
		||||
[R701](https://ipsattendant.it/rilevatore-presenze-r701/) from [I.P.S.
 | 
			
		||||
Informatica](https://ipsinformatica.info/).
 | 
			
		||||
 | 
			
		||||
Unlike the old reader, with this one employees can record their presence via
 | 
			
		||||
PIN, fingerprint, or RFID badge, then the records can be downloaded through the
 | 
			
		||||
official Windows client or via a USB stick.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
The problem is that the client, besides being installable only on Windows and
 | 
			
		||||
requiring an account to perform even offline actions, doesn't meet my dad's
 | 
			
		||||
requirements.
 | 
			
		||||
 | 
			
		||||
It would be appreciated if a report was generated every month for each
 | 
			
		||||
employee, with a table showing the hours worked each day. Instead, the official
 | 
			
		||||
software only allows you to download a list of presences, without any kind of
 | 
			
		||||
division by month or employee, and it doesn't allow exporting everything to a
 | 
			
		||||
`.ods` file.
 | 
			
		||||
 | 
			
		||||
So, in pure "[Stallman when the new Xerox printer
 | 
			
		||||
jams](https://oreilly.com/openbook/freedom/ch01.html)" mode, I decided that the
 | 
			
		||||
best solution was to rewrite everything in an open-source way.
 | 
			
		||||
 | 
			
		||||
## Dumping the records via USB
 | 
			
		||||
 | 
			
		||||
To begin, I tried to download the records using a USB stick, as this method
 | 
			
		||||
doesn't require a Windows PC. I formatted a USB stick in FAT32, and after
 | 
			
		||||
creating a test user and making a few records, I downloaded the data to my
 | 
			
		||||
laptop.
 | 
			
		||||
 | 
			
		||||
Once I opened the contents of the USB stick, I noticed that the reader had
 | 
			
		||||
created two files:
 | 
			
		||||
 | 
			
		||||
* `~tmp.tmp`: which contains the string `usb test!!` repeated 384 times;
 | 
			
		||||
* `AGLog_001.txt`: which contains the records.
 | 
			
		||||
 | 
			
		||||
I believe that the `~tmp.tmp` file is used by the reader only to check if the
 | 
			
		||||
USB stick is writable, so we can ignore it.
 | 
			
		||||
 | 
			
		||||
Opening the `AGLog_001.txt` file, we can start to look at the various fields
 | 
			
		||||
that the reader stores in memory:
 | 
			
		||||
 | 
			
		||||
```csv
 | 
			
		||||
No	Mchn	EnNo		Name		Mode	IOMd	DateTime	
 | 
			
		||||
000001	1	000000001	test      	34	0	2024/04/28  16:04:23
 | 
			
		||||
000002	1	000000001	test      	33	1	2024/04/28  16:05:28
 | 
			
		||||
000003	1	000000001	test      	35	2	2024/04/28  16:08:49
 | 
			
		||||
000004	1	000000001	test     	35	3	2024/04/28  16:09:01
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
* `No` is the record ID
 | 
			
		||||
* `Mchn` is the reader ID
 | 
			
		||||
* `EnNo` is the employee ID who made the record (**En**ployee **No**mber?)
 | 
			
		||||
* `Name` is the employee's name
 | 
			
		||||
* `Mode` is the method by which the employee recorded their presence:
 | 
			
		||||
  * `33` is via fingerprint
 | 
			
		||||
  * `34` is using a PIN
 | 
			
		||||
  * `35` is with the badge
 | 
			
		||||
* `IOMd` is the field containing the employee entrance or exit (**I**n/**O**ut
 | 
			
		||||
  **M**o**d**e ?)
 | 
			
		||||
  * `0` is the first entrance
 | 
			
		||||
  * `1` is the first exit
 | 
			
		||||
  * `2` is the second entrancance
 | 
			
		||||
  * `3` is the second exit
 | 
			
		||||
* `Datetime` is the date and time of the record
 | 
			
		||||
 | 
			
		||||
Considering that I recorded the test records by passing through all the
 | 
			
		||||
entrance and exit modes in order, using the PIN the first time, the fingerprint
 | 
			
		||||
the second time, and the badge the last two times, we can be satisfied with the
 | 
			
		||||
result.
 | 
			
		||||
 | 
			
		||||
We could even write a Python program using the
 | 
			
		||||
[csv](https://docs.python.org/3/library/csv.html) library to extract the data
 | 
			
		||||
we need from this file.
 | 
			
		||||
 | 
			
		||||
But this wouldn't be interesting enough to be a blog post. I don't want to
 | 
			
		||||
enter the device's admin menu, press the `2`, `1`, and `2` keys in order to
 | 
			
		||||
make a dump, then take the resulting file and filter it with a Python script
 | 
			
		||||
without a graphical interface.
 | 
			
		||||
 | 
			
		||||
I want to create a program that runs natively on Windows and Linux and allows
 | 
			
		||||
me to download all the data I care about with a single click, in the format I
 | 
			
		||||
need.
 | 
			
		||||
 | 
			
		||||
Before pulling out [Wireshark](https://wireshark.org/) and trying to sniff some
 | 
			
		||||
packets, I want to try another technique...
 | 
			
		||||
 | 
			
		||||
## Decompiling the closed-source client
 | 
			
		||||
 | 
			
		||||
As [a wise man](https://twitter.com/DebugPrivilege/status/1531661046238388226)
 | 
			
		||||
once said, "All source code is open source if you can read Assembly".
 | 
			
		||||
 | 
			
		||||
Since the company that wrote the code is Italian and the client only works on
 | 
			
		||||
Windows, there's a high chance the code is written in C# on the .NET platform.
 | 
			
		||||
 | 
			
		||||
If this is the case, it should be pretty straightforward to get the source code
 | 
			
		||||
through a decompiler like
 | 
			
		||||
[CodemerxDecompile](https://decompiler.codemerx.com/).
 | 
			
		||||
 | 
			
		||||
So I created a virtual machine with [Windows 10
 | 
			
		||||
AME](https://archive.org/details/windows10-ame-21h1-2021-08-09/) and installed
 | 
			
		||||
the official client at [version
 | 
			
		||||
04.03.02](https://ipsattendant.it/download-programmi-e-manuali/).
 | 
			
		||||
 | 
			
		||||
{{< carousel images="images/03-official-client-installation/*"
 | 
			
		||||
aspectRatio="16-9" interval="1000" >}}
 | 
			
		||||
 | 
			
		||||
Once I installed the official client, I copied the `C:\Program Files
 | 
			
		||||
(x86)\ipsAttendant` directory onto my Linux machine and opened it with
 | 
			
		||||
CodemerxDecompile.
 | 
			
		||||
 | 
			
		||||
As I expected, the code is written in C#, so it's easily readable.
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Searching here and there, I found out the bitter truth: inside the
 | 
			
		||||
`Dichiarazioni.cs` file, there are many interesting methods, such as
 | 
			
		||||
`FK_ConnectNet()`. However, these methods are all imports from a library called
 | 
			
		||||
`FKAttend.dll`.
 | 
			
		||||
 | 
			
		||||
Searching the web, it seems this library has been around for many years, and I
 | 
			
		||||
highly doubt the company that made the reader wrote it themselves. I also found
 | 
			
		||||
the [official DDL
 | 
			
		||||
documentation](</posts/2024/04/reverse-engineering-an-attendance-clock-part-1/FKAttend User's Manual.pdf>),
 | 
			
		||||
but nothing else.
 | 
			
		||||
 | 
			
		||||
Since decompiling a library that even the creator didn't bother to implement
 | 
			
		||||
themselves is not something I'm willing to do, in the next article, we will try
 | 
			
		||||
to reverse-engineer the communication between the client and the device.
 | 
			
		||||