Morphotop Library
Published: 2022-04-18 05:01:25




A while ago, I got my hands on the executable file of the morphotop. The morphotop is a fingerprint reader that can read all of the fingerprints in your hand. After playing with it for a while, I managed to build a C++ library that can communicate with the device.

```
#include "BDS_Common.h"
#include "BDS_OS.h"
#include "BDS_Interface_XCS.h";
#include <iostream>

extern "C" __declspec(dllexport) int LoadLib(TCHAR *file, void ** o_pp_handle)
{
	HINSTANCE h_lib = LoadLibrary(file);
	*o_pp_handle = NULL;
	if(h_lib == NULL)
		return ERROR_LOADLIBRARY;
	*o_pp_handle = h_lib;
	return 0;
}
extern "C" __declspec(dllexport) int GProcAddress(void * i_p_handle,char * i_pc_method, void ** o_pp_procaddress) {
	void * l_p_proc;
	l_p_proc = GetProcAddress((HINSTANCE)i_p_handle,i_pc_method);
	if(l_p_proc == NULL)
		return ERROR_GETPROCADDRESS;
	*o_pp_procaddress = l_p_proc;
	return 0;
}
extern "C" __declspec(dllexport) int resolveInterface (TCHAR * i_pc_fullpath, int i_i_dllType, 
						  interfaceFunction ** o_p_interfaceTable,
						  int * o_i_interfaceTable_count,
						  int * o_i_dllVersion) {
	void * l_p_handle = 0;
	int l_i_result;
	int l_i_dllType;
	void * l_pf_getInterface;
	l_i_result = LoadLib(i_pc_fullpath,&l_p_handle);
	if(l_i_result == 0) {
		l_i_result = GProcAddress(l_p_handle,"getInterface", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_getInterface)l_pf_getInterface)
						 (&l_i_dllType,
						  o_i_dllVersion,
						  o_p_interfaceTable,
						  o_i_interfaceTable_count);
		if (i_i_dllType != l_i_dllType) {
				return ERROR_DLL_TYPE;
			}
		}
	};
	return l_i_result;
}
extern "C" __declspec(dllexport) int EnumerateUsableBiometricDevices (void * l_p_handle, int * const o_p_deviceCount) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_EnumerateUsableBiometricDevices", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_EnumerateUsableBiometricDevices)l_pf_getInterface)
						 (o_p_deviceCount);
		
		}
	
	return l_i_result;
}
extern "C" __declspec(dllexport) int OpenBioDevice (void * l_p_handle, const int i_i_deviceIndex,
				int * o_p_deviceHandle,
				void * const i_p_userData) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_OpenBiometricDevice", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_OpenBiometricDevice)l_pf_getInterface)
						 (i_i_deviceIndex,o_p_deviceHandle,i_p_userData);
		
		}
	
	return l_i_result;
}
extern "C" __declspec(dllexport) int CloseBioDevice (void * l_p_handle, const int i_i_deviceHandle) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_CloseBiometricDevice", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_CloseBiometricDevice)l_pf_getInterface)
						 (i_i_deviceHandle);
		
		}
	
	return l_i_result;
}
extern "C" __declspec(dllexport) int SetDetectionMode (void * l_p_handle, const int    i_i_deviceHandle, 
													   const int    i_i_detectionMode,  const int    i_i_fingerNumber) 
 {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_SetParametersForDetectionMode", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_SetParametersForDetectionMode)l_pf_getInterface)
						 (i_i_deviceHandle,
						 i_i_detectionMode,
						 i_i_fingerNumber);
		
		}
	
	return l_i_result;
}
extern "C" __declspec(dllexport) int GetDetectedImage (void * l_p_handle, const int i_i_deviceHandle,
				const unsigned long i_l_timeout,
				BDS_Image * const o_p_outputImage,
				BDS_DetectionResults * const o_p_results) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_GetDetectedImage", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_GetDetectedImage)l_pf_getInterface)
						 (i_i_deviceHandle,
						 i_l_timeout, o_p_outputImage,o_p_results);
		
		}
	
	return l_i_result;
}

extern "C" __declspec(dllexport) BDS_Image * BDS_GetDirectImage (void * l_p_handle,const int i_i_deviceHandle,const unsigned long i_l_timeout
				,BDS_Image *	o_p_outputImage)
				{
					int l_i_result;
					//o_p_outputImage=(BDS_Image*) new BDS_Image();
				BDS_Image *	o_p_outputImage2=(BDS_Image *) new BDS_Image();
	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_GetDirectImage", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_GetDirectImage)l_pf_getInterface)
						 (i_i_deviceHandle,
						 i_l_timeout, o_p_outputImage2);
		}
	
	return o_p_outputImage2;
				}

extern "C" __declspec(dllexport) int BDS_SetParametersForDirectMode (void * l_p_handle,const int i_i_deviceHandle,const int i_i_samplingMode)
				{
					int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_SetParametersForDirectMode", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_SetParametersForDirectMode)l_pf_getInterface)
						 (i_i_deviceHandle,i_i_samplingMode );
		
		}
	
	return l_i_result;
}
			

extern "C" __declspec(dllexport) int AutoTest (void * l_p_handle,const int      i_i_deviceIndex, 
											   const BDS_TestParameters * const  i_p_testParameters, 
											   BDS_TestResults * const   o_p_testResults) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_Autotest", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_Autotest)l_pf_getInterface)
						 (i_i_deviceIndex,
						 i_p_testParameters, o_p_testResults);
		
		}
	
	return l_i_result;
}

extern "C" __declspec(dllexport) int BDS_SetParametersForLiveMode (void * l_p_handle,
const int i_i_deviceHandle,
const int i_i_samplingMode) {
	int l_i_result;

	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_SetParametersForLiveMode", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_SetParametersForLiveMode)l_pf_getInterface)
						 (i_i_deviceHandle,
						 i_i_samplingMode);
		
		}
	
	return l_i_result;
}
int  ApplicationCallback(const int i_i_deviceHandle,BDS_Image * const i_p_currentImage,const unsigned char * const i_p_inputData,
	 unsigned char * const o_p_outputData,void * const o_p_userData){
       
  return 0;
 }

extern "C" __declspec(dllexport)  int BDS_DefineLiveProcess (void * l_p_handle, const int i_i_deviceHandle,BDS_Callback c) {
	int l_i_result;
    void * l_pf_getInterface=(void*)new int(20);
	
	//o_p_outputImage2=ApplicationCallback;
		l_i_result = GProcAddress(l_p_handle,"BDS_DefineLiveProcess", &l_pf_getInterface);
		std::cout<<l_i_result;
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_DefineLiveProcess)l_pf_getInterface)
						 (0,
						c);
		
		}
		//free(l_pf_getInterface);
	return l_i_result;
}



extern "C" __declspec(dllexport) int BDS_GetBiometricDeviceDescriptor (void * l_p_handle,const int i_i_deviceIndex,char * pointer){
	int l_i_result;
	BDS_DeviceDescriptor * o_p_deviceDescriptor =NULL;
	void * l_pf_getInterface;
		l_i_result = GProcAddress(l_p_handle,"BDS_GetBiometricDeviceDescriptor", &l_pf_getInterface);
		if(l_i_result == 0) {
			l_i_result = ((pf_BDS_GetBiometricDeviceDescriptor)l_pf_getInterface)
						 (i_i_deviceIndex,
						 o_p_deviceDescriptor);
		   pointer =o_p_deviceDescriptor->m_deviceSerial;
		}
	
	return l_i_result;
} 
```
This code is outdated and I am sharing it in hopes that someone can benefit from it. 

a also biult a c# wrapper that use the c++ library 

```
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Morphotop
{
    public unsafe partial class Form1 : Form
    {

        public Form1()
        {
            InitializeComponent();
            //BDS_Callback callback = Callback;

        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
        public struct BDS_Image
        {
            public unsafe uint m_magic;
            public unsafe uint m_version;
            public unsafe uint m_width;
            public unsafe uint m_height;
            public unsafe uint m_flags;
            public IntPtr m_image;
            public unsafe uint m_count;
            public unsafe uint m_checksum;
            public unsafe fixed byte m_rfu[25];
        }
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public unsafe delegate int BDS_Callback(IntPtr i_i_deviceHandle,
                                   BDS_Image* i_p_currentImage, IntPtr i_p_inputData,
                                    IntPtr o_p_outputData, IntPtr i_p_userData);

        public  unsafe int CallbackPointer(IntPtr i_i_deviceHandle, BDS_Image* i_p_currentImage, IntPtr i_p_inputData,
                                    IntPtr o_p_outputData, IntPtr i_p_userData)
        {
            try
            {
                uint size = i_p_currentImage->m_width * i_p_currentImage->m_height;
                byte[] data = new byte[size];
                byte[] height = new byte[i_p_currentImage->m_height];
                byte[] width = new byte[i_p_currentImage->m_width];
                IntPtr pointer = Marshal.AllocHGlobal(data.Length);
                Marshal.Copy(i_p_currentImage->m_image, data, 0, data.Length);
                Marshal.FreeHGlobal(pointer);

                 SetPicture(pictureBox1, ConvertToBitmap(data, width.Length, height.Length));
            }
            catch
            {
            }
            return 0;
        }
        private  void SetPicture(PictureBox img, Bitmap bmp)
        {
            try
            {
                if (img.InvokeRequired)
                {
                    img.Invoke(new MethodInvoker(
                    delegate()
                    {
                        pictureBox1.Image = bmp;
                    }));
                }
                else
                {
                    pictureBox1.Image = bmp;
                }
            }
            catch
            {
            }
        }
        public void Initialize()
        {


            // int res5 = OpenBioDevice(i_p_handle, 0, out device_handle, user_data);
        }
        private void Capture_Click(object sender, EventArgs e)
        {




            int p = BDS_SetParametersForDirectMode(i_p_handle, 1);
            BDS_Image* resdet = BDS_GetDirectImage(i_p_handle, 0, 5000);
            uint size = resdet->m_width * resdet->m_height;
            byte[] data = new byte[size];
            byte[] height = new byte[resdet->m_height];
            byte[] width = new byte[resdet->m_width];
            if (data.Length != null)
            {
                IntPtr pointer = Marshal.AllocHGlobal(data.Length);
                try
                {
                    Marshal.Copy(resdet->m_image, data, 0, data.Length);
                    Marshal.FreeHGlobal(pointer);
                    File.WriteAllBytes("test",data);
                    Bitmap bmp =ConvertToBitmap(data, width.Length, height.Length);
                    bmp.Save(Directory.GetCurrentDirectory()+"\\test.jpg");
                    pictureBox2.Image = bmp;
                }
                catch
                {

                }
            }
           
        }
        private Bitmap ConvertToBitmap(byte[] image_data,int width,int height)
        {
            try
            {
                int Width = width;
                int Height = height;
                var b = new Bitmap(Width, Height, PixelFormat.Format8bppIndexed);

                ColorPalette ncp = b.Palette;
                for (int i = 0; i < 256; i++)
                    ncp.Entries[i] = Color.FromArgb(255, i, i, i);
                b.Palette = ncp;
                var BoundsRect = new Rectangle(0, 0, Width, Height);
                BitmapData bmpData = b.LockBits(BoundsRect,
                                                ImageLockMode.WriteOnly,
                                                b.PixelFormat);

                IntPtr ptr = bmpData.Scan0;

                int bytes = width * b.Height;
                var rgbValues = new byte[bytes];
                Marshal.Copy(image_data, 0, ptr, bytes);
                b.UnlockBits(bmpData);
                return b;
            }
            catch
            {
                return null;
            }
        }



        private void Form1_Load(object sender, EventArgs e)
        {
            Initialize(textBox1);
        }



       private IntPtr i_p_handle;
        public void Initialize(TextBox result)
        {
            i_p_handle = IntPtr.Zero;
            IntPtr o_pp_procaddress = IntPtr.Zero;
            IntPtr o_p_interfaceTable = IntPtr.Zero;
            IntPtr o_i_interfaceTable_count = IntPtr.Zero;
            IntPtr o_i_dllVersion = IntPtr.Zero;
        
            IntPtr o_p_deviceCount = IntPtr.Zero;
            IntPtr device_handle = IntPtr.Zero;
            IntPtr img2 = IntPtr.Zero;
            IntPtr r = IntPtr.Zero;
            int user_data = 300;
            int re = 0;
            result.AppendText("Loading Library......." + Environment.NewLine);
            re = LoadLib(Directory.GetCurrentDirectory() + "\\SDKServices.dll", out i_p_handle);
            if (re == 0)
            {
                result.AppendText("Library Loaded No ERRORS" + Environment.NewLine);
                result.AppendText("Resolving interface" + Environment.NewLine);
                re = resolveInterface(Directory.GetCurrentDirectory() + "\\SDKServices.dll", o_pp_procaddress, out o_p_interfaceTable, out o_i_interfaceTable_count, out o_i_dllVersion);
                if (re == 0)
                {
                    result.AppendText("Interface resolved" + Environment.NewLine);
                    result.AppendText("Enumerating devices" + Environment.NewLine);
                    re = EnumerateUsableBiometricDevices(i_p_handle, out o_p_deviceCount);
                        OpenBioDevice(i_p_handle,0,out r,user_data);
                        SetupLiveMode(0,i_p_handle);
                    if (re == 0)
                    {
                        result.ForeColor = Color.Black;
                        result.AppendText("device enumerated" + Environment.NewLine);
                    }
                    else
                    {
                        result.AppendText("device could not be enumerated" + Environment.NewLine);
                    }
                }
                else
                {
                    result.AppendText("Interface could not be resolved" + Environment.NewLine);
                }
            }
            else
            {
                result.ForeColor = Color.Black;
                result.AppendText("could not load library" + Environment.NewLine);
            }
        }
        public void OpenDevice(TextBox result, IntPtr i_p_handle, IntPtr o_p_deviceHandle, int i_p_userData)
        {
            int resu = OpenBioDevice(i_p_handle, 0, out o_p_deviceHandle, i_p_userData);
            if (resu == 0)
            {
                result.AppendText("Biometric Device Opened" + Environment.NewLine);
            }
            else
            {
                result.AppendText("Could not open Biometric device" + Environment.NewLine);
            }
        }

        public void CloseDevice(TextBox result, IntPtr i_p_handle, int o_p_deviceHandle)
        {
            int resu = CloseBioDevice(i_p_handle, o_p_deviceHandle);
            if (resu == 0)
            {
                result.ForeColor = Color.Black;
                result.AppendText("Biometric Device Closed" + Environment.NewLine);
            }
            else
            {
                result.ForeColor = Color.Red;
                result.AppendText("Could not close Biometric device" + Environment.NewLine);
            }
        }
        public BDS_Callback callback1;
        public void SetupLiveMode(int SamplingMode, IntPtr i_p_handle)
        {
             callback1 = new BDS_Callback(CallbackPointer);
             int res = BDS_DefineLiveProcess(i_p_handle, SamplingMode, callback1);
        }
        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int LoadLib(String path, out IntPtr i_p_handle);

        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl)]
        public extern static int GProcAddress(IntPtr i_p_handle, string i_pc_method, out IntPtr o_pp_procaddress);

        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int resolveInterface(String path, IntPtr i_i_dllType, out IntPtr o_p_interfaceTable, out IntPtr o_i_interfaceTable_count, out IntPtr o_i_dllVersion);


        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int EnumerateUsableBiometricDevices(IntPtr path, out IntPtr o_p_deviceCount);


        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int OpenBioDevice(IntPtr path, int i_i_deviceIndex, out IntPtr o_p_deviceHandle, int i_p_userData);


        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int CloseBioDevice(IntPtr path, int i_i_deviceHandle);

        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int SetDetectionMode(IntPtr path, IntPtr i_i_deviceHandle, int i_i_detectionMode, int i_i_fingerNumber);
        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl)]
        public extern unsafe static BDS_Image* BDS_GetDirectImage(IntPtr path, int i_i_deviceHandle, ulong i_l_timeout);
        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int BDS_SetParametersForDirectMode(IntPtr hadle, int sample);
        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int BDS_SetParametersForDirectMode(IntPtr path, IntPtr i_i_deviceHandle, int i_i_samplingMode);
        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int BDS_DefineLiveProcess(IntPtr l_p_handle, int a, BDS_Callback c);

        [DllImport("SSB.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
        public extern static int BDS_DefineLiveProcess(int l_p_handle, BDS_Callback bds);

        private void Close_Click(object sender, EventArgs e)
        {
            CloseDevice(textBox1, i_p_handle, 0);
        }
        IEnumerable<Rectangle> FindImageTiles(Bitmap compositeImage)
        {
            var result = new List<Rectangle>();

            // Scan for a non-empty region that hasn't already been "captured"
            for (var x = 0; x < compositeImage.Width; x++)
            {
                for (var y = 0; y < compositeImage.Height; y++)
                {
                    // Only process the pixel if we don't have a rectangle that
                    // already contains this and if it's not empty
                    if (!result.Any(r => r.Contains(x, y))
                        && compositeImage.GetPixel(x, y).A != 0)
                    {
                        // Now that we've found a point, create a rectangle
                        // surrounding that point, then expand outward until
                        // we have a bounding rectangle that doesn't intersect
                        // with the tile
                        var rect = new Rectangle(x - 1, y - 1, 2, 2);
                        bool foundBounds = false;
                        while (!foundBounds)
                        {
                            var xRange = Enumerable.Range(rect.Left, rect.Right)
                                .Where(px => px >= 0 && px < compositeImage.Width);
                            var yRange = Enumerable.Range(rect.Top, rect.Bottom)
                                .Where(py => py >= 0 && py < compositeImage.Height);

                            // Adjust the top
                            if (rect.Top >= 0
                                && xRange
                                    .Select(bx => compositeImage.GetPixel(bx, rect.Top))
                                    .Any(p => p.A != 0))
                            {
                                rect.Y--;
                                rect.Height++;
                            }
                            else if (rect.Bottom < compositeImage.Height
                                && xRange
                                    .Select(bx => compositeImage.GetPixel(bx, rect.Bottom))
                                    .Any(p => p.A != 0))
                            {
                                rect.Height++;
                            }
                            else if (rect.Left >= 0
                                && yRange
                                    .Select(by => compositeImage.GetPixel(rect.Left, by))
                                    .Any(p => p.A != 0))
                            {
                                rect.X--;
                                rect.Width++;
                            }
                            else if (rect.Right < compositeImage.Width
                                && yRange
                                    .Select(by => compositeImage.GetPixel(rect.Right, by))
                                    .Any(p => p.A != 0))
                            {
                                rect.Width++;
                            }
                            else
                            {
                                foundBounds = true;
                            }
                        }
                        result.Add(rect);
                    }
                }
            }

            return result;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IEnumerable<Rectangle> rec = FindImageTiles((Bitmap)pictureBox2.Image);
            Image img = pictureBox2.Image;
            Graphics newGraphics = Graphics.FromImage(img);
            foreach(Rectangle r in rec){
                newGraphics.DrawRectangle(new Pen(Color.Black, 2), r);
            }
        }
    }
}
```
you can find the entire project in here https://github.com/medsaid2001/morphotop-library