Ein USB-Dongel

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von Amelie.

    Ein USB-Dongel

    Moin moin

    Ich habe mich nun etwas mit Sicherheit usw beschäftigen müssen. Im www und hier fand ich etwas über Dongels usw.
    Habe nun versucht so etwas zu schreiben.

    Mit einem ähnlichem Code wie der gezeigte habe ich einen Hash von einem USB-Stick generiert und in einer DB hinterlegt. Dazu habe ich mehrere Werte genommen.

    Fünf USB-Sticks habe ich frisch formatiert und immer die identische Config-Datei drauf kopiert, welche als "versteckt" markiert ist.
    Nach ersten Test, komme ich in die "Sub StartProgramm()" nur mit dem richtigen Stick.

    Ist das ein Ansatz der soweit OK wäre? :?:

    Die config-Datei auf dem USB-Stick

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Amelie“ ()

    @petaod

    OK ich habe das mal mit 2 Sticks ausgetestet. Daran hatte ich gar nicht gedacht. :thumbup:
    Dann wird tatsächlich je nach Laufwerksbuchstabe das Programm beendet, weil dann ggf der "falsche" Stick zuerst geprüft wird.

    hmmm...
    Hast du einen Tip wie ich das lösen könnte?
    Über den LW-Buchstaben ist wohl keine gute Sache??
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    @Amelie

    Ein Usb-Stack besitzt doch die Parameter
    - VID = Vendor-ID
    - PID = Product-ID

    Über z.B. WMI kann geschaut werden, ob ein entsprechender Usb-Stack mit der Kennzeichnung PID_xxxxx + VID_xxxxx auf dem lokalem Computer eingesteckt ist.

    Die beiden Parameter werden gerne (z.B. mit Hash sha256 ähnlich im Ablauf wie in der Kryptography) für so Donglezwecke verwendet. Ich würde mich mal auf diesem Gebiet einarbeiten. Es gibt bestimmt auch noch Hilfe auf Github oder eventuell findet man Infos mit Google.

    Ob die beiden Werte für die Donglenutzung dann bei der Installation (sofern das gewollt ist) in die Registry gespeichert werden sollen, lass ich mal offen, weil wahrscheinlich dann Adminrechte gefordert sind.

    Edit: Wie petaod unten schreibt, eventuell so

    C#-Quellcode

    1. using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_PnPEntity"))
    2. using (var devices = searcher.Get()) //ManagementObjectCollection
    3. {
    4. foreach (var device in devices) //ManagementBaseObject
    5. {
    6. string device_id = (string)device.GetPropertyValue("DeviceID");
    7. //stuff
    8. }
    9. }


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    @exc-jdbi und @petaod
    - VID = Vendor-ID- PID = Product-ID

    Da werde ich mal drüber lesen.

    EDIT: 14:30 (falsch geklickt)
    Debugausgaben:

    XML-Quellcode

    1. =========================
    2. Device Name: USB Mass Storage Device
    3. Vendor ID (VID): ABCD
    4. Product ID (PID): 1234
    5. =========================
    6. Device Name: USB Mass Storage Device
    7. Vendor ID (VID): ABCD
    8. Product ID (PID): 1234
    9. =========================


    2 USB Sticks vom selben Hersteller aber unterschiedlich formatiert, ergeben die gleichen Werte.
    Ein anderer Stick (anderer Hersteller) hat andere Werte.

    XML-Quellcode

    1. =========================
    2. Device ID: \\.\PHYSICALDRIVE5
    3. Serial Number: 03003205062221230832
    4. =========================
    5. Device ID: \\.\PHYSICALDRIVE4
    6. Serial Number:
    7. =========================


    Dann geben einige diese SerienNr aus, andere wiederum geben gar nichts aus. :cursing:

    Ratlos bin ?(
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Amelie“ ()

    Mit welchem Code kommen diese Ausgaben (die für die unterschiedlichen Sticks auch von den Ausgabeparametern interessanterweise unterschiedlich sind)?
    Was kommt hierbei raus (gefunden in meiner Sammlung alter Codes)?

    VB.NET-Quellcode

    1. For Each Drive In IO.DriveInfo.GetDrives.Where(Function(x) x.DriveType = IO.DriveType.Removable)
    2. Dim FileSystemObject = DirectCast(Microsoft.VisualBasic.CreateObject("Scripting.FileSystemObject"), Scripting.FileSystemObject)
    3. Dim Stick = FileSystemObject.GetDrive(Drive.Name)
    4. Console.WriteLine($"Laufwerk {Stick.DriveLetter} ({Stick.VolumeName}): ID = {Stick.SerialNumber}")
    5. Next

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Amelie schrieb:

    Dann geben einige diese SerienNr aus, andere wiederum geben gar nichts aus.
    Dann verwende nur Sticks als Dongle, die Deine Anforderungen erfüllen.
    Und:
    Überwache das Ziehen von USB-Sticks, do kann keiner Deinen einen Dongle an mehreren Rechnern verwenden.
    C#-Code ohne weiteren Kommentar.
    Spoiler anzeigen

    C#-Quellcode

    1. /// <summary>
    2. /// behandelt das Stecken und Abziehen von USB-Sticks
    3. /// </summary>
    4. protected override void WndProc(ref Message m)
    5. {
    6. const int WM_DEVICECHANGED = 0x0219; // USB-Stick geändert
    7. const int DBT_DEVICEARRIVAL = 0x8000; // USB-Stick gesteckt
    8. const int DBT_DEVICEREMOVECOMPLETE = 0x8004; // USB-Stick entfernt
    9. if (m.Msg == WM_DEVICECHANGED)
    10. {
    11. int wParam = m.WParam.ToInt32();
    12. // USB-Stick gesteckt oder entfernt
    13. if (wParam == DBT_DEVICEARRIVAL)
    14. {
    15. // zu implementieren
    16. this.UsbReceived();
    17. }
    18. else if (wParam == DBT_DEVICEREMOVECOMPLETE)
    19. {
    20. // zu implementieren
    21. this.UsbRemoved();
    22. }
    23. }
    24. base.WndProc(ref m);
    25. }
    Ich hab noch nen VB.NET-Snippet gefunden:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. 'https://tempuzfugit.wordpress.com/2007/10/08/external-storage-unit-detection-with-c-in-net-usb-card-readers-etc/
    3. 'https://www.vb-paradise.de/index.php/Thread/11579-Erkennen-wann-ein-Laufwerk-hinzugef%C3%BCgt-bzw-entfernt-wurde-USB-Stick/
    4. Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
    5. Const WM_DEVICECHANGE As Integer = &H219
    6. Const DBT_DEVICEARRIVAL As Integer = &H8000
    7. Const DBT_DEVICEREMOVECOMPLETE As Integer = &H8004
    8. Dim wParam = msg.WParam.ToInt32()
    9. If msg.Msg = WM_DEVICECHANGE Then
    10. If wParam = DBT_DEVICEARRIVAL Then
    11. Me.RichTextBox1.AppendText("Neues Gerät" & Environment.NewLine)
    12. ElseIf wParam = DBT_DEVICEREMOVECOMPLETE Then
    13. Me.RichTextBox1.AppendText("Gerät abgezogen" & Environment.NewLine)
    14. End If
    15. End If
    16. MyBase.WndProc(msg)
    17. End Sub
    18. End Class

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VaporiZed
    2 Sticks vom selben Hersteller aber unterschiedlich formatiert.

    XML-Quellcode

    1. Laufwerk E:\ (MYBUDGET): ID = Nicht verfügbar
    2. Laufwerk Z:\ (MyBudget): ID = Nicht verfügbar


    Alles Codeschnipsel die ich zu diesem Thema gefunden hatte. War meist alles in C# musste ich dann mit dem Converter umbauen...
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Try
    4. Dim searcher2 As New ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'")
    5. For Each queryObj As ManagementObject In searcher2.Get()
    6. Dim deviceId As String = queryObj("DeviceID").ToString()
    7. Dim serialNumber As String = queryObj("SerialNumber").ToString()
    8. Console.WriteLine("Device ID: " & deviceId)
    9. Console.WriteLine("Serial Number: " & serialNumber)
    10. Console.WriteLine("=========================")
    11. Next
    12. '--------------------------------------------
    13. Dim searcher3 As New ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'")
    14. For Each queryObj As ManagementObject In searcher3.Get()
    15. Dim deviceName As String = queryObj("Caption").ToString()
    16. Dim deviceId As String = queryObj("DeviceID").ToString()
    17. Dim manufacturer As String = queryObj("Manufacturer").ToString()
    18. Dim model As String = queryObj("Model").ToString()
    19. Dim capacity As String = queryObj("Size").ToString()
    20. Dim description As String = queryObj("Description").ToString()
    21. Dim usbVersion As String = queryObj("InterfaceType").ToString()
    22. Console.WriteLine("Device Name: " & deviceName)
    23. Console.WriteLine("Device ID: " & deviceId)
    24. Console.WriteLine("Manufacturer: " & manufacturer)
    25. Console.WriteLine("Model: " & model)
    26. Console.WriteLine("Capacity: " & capacity)
    27. Console.WriteLine("Description: " & description)
    28. Console.WriteLine("USB Version: " & usbVersion)
    29. Console.WriteLine("=========================")
    30. Next
    31. '-------------------------------
    32. Dim removableDrives = DriveInfo.GetDrives().Where(Function(drive) drive.DriveType = DriveType.Removable)
    33. For Each drive In removableDrives
    34. Dim volumeName As String = drive.VolumeLabel
    35. Dim driveLetter As String = drive.Name
    36. Dim serialNumber As String = GetDriveSerialNumber(driveLetter)
    37. Console.WriteLine("Laufwerk " & driveLetter & " (" & volumeName & "): ID = " & serialNumber)
    38. Next
    39. Catch ex As ManagementException
    40. MessageBox.Show("Ein Fehler ist aufgetreten: " & ex.Message)
    41. End Try
    42. End Sub
    43. Private Function GetDriveSerialNumber(driveLetter As String) As String
    44. Try
    45. Dim drive As New Management.ManagementObject("Win32_LogicalDisk.DeviceID=""" & driveLetter & """")
    46. drive.Get()
    47. Return drive("VolumeSerialNumber").ToString()
    48. Catch ex As Exception
    49. Return "Nicht verfügbar"
    50. End Try
    51. End Function
    52. End Class




    @RodFromGermany
    Danke, den Code nutze ich schon. Habe mir dafür mal vor einiger zeit eine Klasse gebaut und noch einen Timer dazu :)
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    und noch einen Timer dazu
    Wozu brauchst Du einen Timer?
    Das macht doch die WndProc().
    Wenn Du eine Pizza bestellst, siehst Du auch nicht alle 5 Minuten aus dem Fenster um zu sehen, ob der Pizza-Mensch da ist, Du wartgest darauf, dass er klingelt. ;)

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Ich habe mir damit ein weiteres Event gemacht.
    Wenn der Stick eingesteckt/abgezogen wird feuert nach xx-Sekunden das weitere Event ...


    (Wenn ich Pizza bestelle, renne ich dem Lieferanten entgegen.. :D :D )
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    feuert nach xx-Sekunden das weitere Event ...
    um zu...?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich seh gerade, das mit dem PID/VID hat funktioniert.

    Was mich aber trotzdem ein bisschen erstaunt, ist das hier gleiche Id's von unterschiedlichen Usb-Stacks bestehen, das habe ich nicht direkt erwartet. Einen solchen Fall hatte ich bei mir noch nie.

    Aber wie ich erkennen kann, gibts ja noch die Serial Number, und die sollte dann wirklich bei jedem Stack anders sein, und die wird doch auch gleich mitgeliefert mit meinem oben erwähnten Code.

    Somit ist auch der Zugriff auf das richtige "Gerät" gewährleistet, und die entsprechenden Informationen, die für die Dongle-Auflösung gebraucht werden, hast du ja schon versteckt hinterlegt. Ich hätte da zwar eine verkryptete Datei auf dem USB-Stack gelegt, dann muss es auch nicht versteckt werden.

    EDIT und PS. Ich habe hier meinen 1000'sten Beitrag geleistet nach 8 Jahren 4 Monaten und ein paar gequetschte :D


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „exc-jdbi“ ()

    @RodFromGermany

    Das war nur eine Übung von mir bzgl Klassen und Events. Hatte keine besondere Funktion.

    @exc-jdbi
    Die SerialNumbers sind bei einigen Sticks nur die "VolumenSerials" bei anderen bekomme ich auch die Manufactor-SerialNumbers.

    Aber anscheinend ändert sich die "VolumenSerials" bei jedem Formatieren und wäre somit auch "unique" :?: :?:
    Dann wäre das ein Ansatz für den USB-Stick eindeutig zu indentifizieren :?:
    Ich hätte da zwar eine verkryptete Datei auf dem USB-Stack gelegt

    Ich hatte sie nicht verkyptet aber schon vorhanden :)

    Spoiler anzeigen

    XML-Quellcode

    1. USB Drive Info:
    2. Device Name: General UDisk USB Device
    3. Device ID: \\.\PHYSICALDRIVE4
    4. Manufacturer: (Standardlaufwerke)
    5. Model: General UDisk USB Device
    6. Capacity: 8052549120
    7. Description: Laufwerk
    8. USB Version: USB
    9. Manufactor Serial Number:
    10. Partition Size: 7761064448 Bytes
    11. =========================
    12. USB Drive Info:
    13. Device Name: Laufwerk
    14. Device ID: \\.\PHYSICALDRIVE5
    15. Manufacturer: (Standardlaufwerke)
    16. Model: Laufwerk
    17. Capacity: 30762547200
    18. Description: Laufwerk
    19. USB Version: USB
    20. Manufactor Serial Number: 03003205062221230832
    21. Partition Size: 30765199360 Bytes
    22. =========================
    23. Drive Info:
    24. Device Name: I:
    25. Device ID: I:
    26. Volumen Serial Number: 36F68BA3
    27. Volume Label: Bilder
    28. Size: 30765199360 bytes
    29. Free Space: 30665457664 bytes
    30. File System: NTFS
    31. Compressed: False
    32. Block Size: 0 bytes
    33. Supports Quotas: True
    34. Supports Compression: True
    35. Volume Dirty: False
    36. Drive Type: Removable Disk
    37. Install Date:
    38. Number of Blocks: 0
    39. PNP Device ID:
    40. =========================
    41. Drive Info:
    42. Device Name: Z:
    43. Device ID: Z:
    44. Volumen Serial Number: 3C5AB570
    45. Volume Label: MyBudget
    46. Size: 7761064448 bytes
    47. Free Space: 7759162880 bytes
    48. File System: exFAT
    49. Compressed: False
    50. Block Size: 0 bytes
    51. Supports Quotas: False
    52. Supports Compression: False
    53. Volume Dirty: False
    54. Drive Type: Removable Disk
    55. Install Date:
    56. Number of Blocks: 0
    57. PNP Device ID:
    58. =========================

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Ich könnte mir schon vorstellen, das die unique ist. Trotzdem würde ich mich lieber auf die Hardware-Attribute beziehen wollen.

    Das die Seriennummer zum Teil nicht auslesbar sind finde ich auch nicht den Hit. Eventuell auf ein USB-Stick wechseln, wo diese Informationen auslesbar sind. Ist ja schon von ROD gesagt worden.

    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „exc-jdbi“ ()

    Meine 2Cent zum Thema USB Dongle.

    Das letzte mal das ich so ein USB Dongle gesehen habe , ist schon über 20 Jahre her. Davor gab es die Dinger für den Parallel-Port. Heute setzt man eher auf andere Verfahren um seine Software am unerlaubtem Verwenden zu schützen. Zu bedenken wäre auch, das jeder Schutz irgendwann umgangen werden kann. Spätestens dann, wenn die richtigen Stellen im Code gefunden wurden, um aus If Key True in ein If Not Key True gepatcht wurde oder ein passender Dongleemulator zum Einsatz kommt, ist der Schutz dahin. Daher sollte man sich auch die Frage stellen, ist die Software so schützendswert, das ein Schutz vor unerlaubten Einsatz nötig ist und welchen Aufwand/Kosten man dazu treiben möchte. Mal davon Abgesehen das ein Hardware-Dongle ein Steckplatz am Gerät belegt, leicht kaputt oder verloren gehen kann und am Ende bleibt Elektroschrott über.

    Wenn ich mich recht erinnere, waren die USB-Dongle seiner Zeit keine handelsüblichen USB-Sticks die man im Laden um die Ecke kaufen konnte und wurden auch nicht im System als Laufwerk angezeigt. Da war nur ein spezieller Chip drauf mit dem man nur verschlüsselt kommunizieren konnte. Wahrscheinlich wurde der USB-Dongle als HID-Device gelistet und man benötigte eine spezielle Software/DLL für die Kommunikation. Der USB-Dongle selber sollte ja auch nicht so einfach kopierbar sein. Das die Chips in handelsüblichen Sticks manipulierbar sind, ist ja auch kein Geheimnis. Da wird mal eben aus einem 32MB Stick ein 1TB Stick. Da liegt es sehr nahe das auch die PID/VID manipuliert werden können.
    Mfg -Franky-

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „-Franky-“ ()

    Da muss ich dir natürlich recht geben.

    Ich habe auch Jahren mal einen versuch gestartet, und ich habe das einfach so gemacht, auch wenn der Stick kopiert wird, kein Nutzen daraus gemacht werden kann, da alle relevanten Keys verkryptet waren.

    -Franky- schrieb:

    If Key True in ein If Not Key True

    Ist natürlich gar nicht gut, dass muss anders gelöst sein, und zwar so, dass die verwendeten Keys und die verwendeten Daten gebraucht werden, um das Programm überhaupt zu starten.

    Ich habe mir dazu sogar ein Passwort beim Starten verlangen lassen. Auch ist beim ersten Aufstarten des Programmes eine kleine Installation gemacht worden, wo alle relevanten Daten verkryptet auf dem Stick abgespeichert worden sind, und aus dem dann ein Masterpasswort, dass während der Laufzeit im Speicher gehalten worden ist, erzeugt worden ist. Diese Infos sind auch nach korrekten beenden des Programms immer wieder anders zusammengestellt worden.

    Es ist klar eine primitive Art und Weise und für den professionellen Einsatz nicht empfehlenswert, aber für den Ottonormalgebrauch hat es funktioniert.

    Freundliche Grüsse

    exc-jdbi
    Alles eine Frage von Aufwand und Kosten gegenüber von Nutzen. Nicht mal nahmenhafte Hersteller von Software schaffen es einen geeigneten Schutz einzubauen. Es ist immer nur eine Frage der Zeit bis ein Schutz ausgehebelt wird. Soweit mir bekannt, gibt es solche speziellen USB-Dongle immer noch. Kosten aber weit über 100 Euro das Stück.

    Wenn dann sollte es schon ein Stick sein der nicht als Laufwerk erkennbar ist. Einfach vom einem DAU ausgehen: Uii, ein USB Laufwerk wo ich Daten drauf schreiben und mit nach Hause nehmen kann. ;) Meinst der gibt freiwillig zu das der eine Stick geklaut hat.
    Mfg -Franky-

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „-Franky-“ ()

    Für mich sollte das ganze mehr eine Übung werden als tatsächlich irgendeine Software zu schützen.
    Klar dieses kleine "HeimFinazProg" für mein Opa kann ich ein bissel absichern aber das war es auch schon.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    @Amelie
    Ich habe mich vor Jahren auch mit diesem Thema auseinandergesetzt und mit "normalen" USB-Sticks oder SD-Karten keine Lösung gefunden die meine Softwareprodukte vor unbefugter Verwendung schützen könnte. Daher habe ich auf ein Produkt einer darauf spezialisierten Firma zurückgegriffen. Den ENKEY USB-Stick.

    Diese USB-Sticks sind preislich akzeptabel und damit schütze ich jede meiner Softwarelizenzen ohne Kompromisse.
    Die Dongles haben auch zusätzlich etwas Speicherplatz - somit kann ich dort auch Lizenz-Laufzeitinformationen und andere lizenzspezifische Dinge ablegen.

    Diese Dongles kann ich vorbehaltlos empfehlen.
    Ich habe von 2014 bis heute knapp 5700 Stück davon mit meinen verschiedenen Softwarelizenzen ausgeliefert.
    Ausfallsquote bisher: 2 Stück !!!!

    hs-securityware.com/enky-lc/enky_lc.html

    Wie man sieht, habe ich auch immer genügend auf Vorrat ;-).

    @-Franky-
    Soweit mir bekannt, gibt es solche speziellen USB-Dongle immer noch. Kosten aber weit über 100 Euro das Stück.

    Nene - ich bezahle bei 800 Stück 8,70 pro Stück. Nur die Sticks mit "viel" Speicher drauf kosten mehr. Aber die braucht man i.d.R. nicht.

    Und zu Deinem Post davor: Jeder Großkunde erhält einen anderen Dongle-Grundschlüssel.
    Somit ist es ausgeschlossen, dass Softwarekunde von X einen Dongle von Y verwenden kann oder dass sich einfach jemand solche Dongles kauft und damit was anfangen kann.
    Selbstverständlich muss der Code so gestaltet sein, dass der nicht so einfach im Quellcode ausgehebelt werden kann.
    Und es kommt immer darauf an wie teuer eine Software ist, wie verbreitet diese ist und ob es sich für Hacker lohnt hier zu "hacken".


    Bilder
    • 20230805_201041.jpg

      3,46 MB, 4.624×2.084, 62 mal angesehen
    • 20230805_201052.jpg

      2,65 MB, 4.624×2.084, 67 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „dive26“ ()