The software, when starting, should launch an https
(so it can't just be sniffed easily;-) request to your server, identifying itself (however it is that you choose to identify, e.g. a serial number or whatever), and the server's response will tell it what to do (run normally, or terminate, or ask the user to register -- whatever).
Of course, any competent hacker will find and disable the part of your code where you're sending the request and dispatching on the answer, but then you already do know that everything can easily be cracked;-).
A less-easily crackable approach would be to keep some crucial part of the functionality on your server, so that the client's basically useless (or at least less useful) if it hasn't checked in with your server and obtained a token to be used in other "functionality requests" during a session.
Hard to tell, without knowing a lot more about your app, if there are bits and pieces of functionality in your app that lend themselves well to this treatment, but for example you could delegate in this way any kind of cryptographic functionality (encrypting, decrypting, signing, ...) -- if only your server knows the secret/private keys to be used for such purposes, and only performs the functionality for application sessions that have properly registered and been authorized, suddenly it's become very hard for even a good hacker to work around your registration and authorization system.