Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Monday, May 24, 2010

Migrating and Cracking Tritek Legal Case Management

In my development of the MerusCase module that does a data migration from Tritek to MerusCase, I have thoroughly decoded their database schema.  What a mess!  I had to develop contact 'de-duping' software using what we call 'fuzzy matching' via a Levenshtein metric.  That was really intriguing to develop.

However, in order to properly map data from their system to ours, I needed a working copy of the software to reference from and see how that data was being stored in their archaic dBase (Microsoft FoxPro) format. It's funny that Microsoft has officially announced the death of FoxPro, i.e. they have announced the dates after which they will no longer support the product.  It's even funnier that if Tritek has any chance of keeping up with technology they will have to start their app from scratch.  Anyone who as ever used the program realizes how shoddy the user interface is -- irritating to navigate, an eyesore to look at (no taste for aesthetics whatsoever!), and a counter-intuitive approach to UI design.

Apparently Tritek's tampering check is easy to crack.  First off, if you rename the xmgmt.exe file with a .txt extension and open it up in TextPad, you'll see that all the FoxPro code is embedded in plain text.  That is, you can see exactly what the developers wrote that make the application run and do what it does.  If you do a search for 'tampered' or 'exempt' you will find the dialog box that tells you to buy a license, and you will also find the code that does the security check.

All it does is do a 'dir x: > WORK\vsno.txt' on the drive that your data sits on, saves the output into the WORK folder, looks for 'Volume Serial Number' in that text file, because it grabs the 9-char s/n for your drive.  It then hashes it and computes the corresponding 8 to 11 digit integer using a built-in FoxPro hash function (SYS 2007).  That integer is compared to the value contained in serno.dbf file, located in your data folder.  There are 'backdoors' aka Tritek Maintenance logins hard-coded too (see code snippet below).  I could run a brute force attack on those codes using a utility like MDCrack to find out the universal volume-s/n they use...

Fortunately, there is a simple command-line utility that allows you to change your drive's serial number.  This has no effect to anything else, so far as I can think of.  Nothing uses HDD serial numbers except for the occasional 15-year old p.o.s. software (Tritek for one!).  Download volumeid.exe from Microsoft Technet (it's free) or from here.  It's usage is simple: volumeid <driveletter:> xxxx-xxxx.  You'll have to reboot for changes to take effect.

Maybe if I have time in the future, I'll throw together a little script that will disable or patch tritek to completely bypass security checks altogether.  In the world of cracking, a bypass may be as simple as converting a machine code instruction 'jump if equal (je)' to 'jump if not equal (jne)'.  =)


a="dir "+xdata+" >"+xwork+"\vsno.txt"
RUN &a
b=xwork+"\vsno.txt"
a=FILETOSTR(b)
c="Volume Serial Number is "
L=LEN(c)
d=AT(c,a)
d=d+L
z=SUBSTR(a,d,9)
a=SYS(2007,z,0,1)
b=a
a=a+a
L=LEN(a)
SELECT serno
vtampered=.f.
z=ALLTRIM(vsno)
LL=LEN(SYS(2007,z,0,1))
    IF (b="446519453" .or. b="487413866" .or. b="1505040575" .or. ;
    b="3629040784" .or. b="659246687" .or. b="140427344" .or. ;
    b="3772951423")
*!*        IF (b="446519453" .or. b="487413866" .or. b="1505040575" .or. ;
*!*        b="3629040784" .or. b="659246687")
    usesmsg="TRITEK MAINTENANCE LOGIN"
    thisform.uses1.visible=.t.
    xe=0

Thursday, February 4, 2010

MooTools Users: Implement a Hash.sort method

I notice that Firefox seems to maintain the order of key:value pairs in objects when iterating over them, while Safari and Chrome seem to sort the object internally (within their respective JS engines).  I  noticed this especially when making select elements.  I store the options as an object, then when drawing the page, I iterate over that  object making option elements. 
For example, I am making a select box that lists users  alphabetically.  Users are identified in the database by an id: 

 
var foo = new Element('select').inject($$('body')[0]); 
var options = {5082:'User A', 5085:'User B', 5074:'User C'} 
$H(options).each(function(name,id){ 
  new Element('option', {text:name, value:id}).inject(foo); 

}); 
In Firefox the select box would present users in order: A,B,C, but in the others, users would appear in order by id: C,A,B.  A neat function  for tackling this sort of problem would be Hash.sort. 
 
/* 
        Function: Hash.sort 
                Takes {c:0, a:1, b:2} and returns [{a:1},{b:2},{c:0}] 
*/ 
Hash.Implement({ 
sort:function(fn){ 
        var out = [], 
                keysToSort = this.getKeys(), 
                m = this.getLength(); 
        (typeof fn == 'function') ? keysToSort.sort(fn) : keysToSort.sort(); 
        for (var i=0; i<m; i++){ 
                var o = {}; 
                o[keysToSort[i]] = this[keysToSort[i]]; 
                out.push(o); 
        } 
        return out; 

} 
}); 
____________ 
 
Usage: 

 
$H({'a':1,'z':2,'c':3,'b':4}).sort() 

 
Results In: 

 
[Object { a=1}, Object { b=4}, Object { c=3}, Object { z=2}] 
______________________ 

 
Then our select box routine becomes: 

 
var foo = new Element('select').inject($$('body')[0]); 
var options = {5082:'User A', 5085:'User B', 5074:'User C'} 
$H(options).sort().each(function(el){ 
  $each(el,function(name, id){ 
    new Element('option', {text:name, value:id}).inject(foo); 
  }); 

}); 
_______ 
 
Ruby programmers may recognize this method (http://ruby-doc.org/core/ 
classes/Hash.html#M002865).

Monday, January 18, 2010

Chomp your PHP for good health.

We had some weird problems in testing one of our applications today. It turned out to be a newline after a ?> tag in a core config php file, so anything being outputted was preceded by a newline. Normally this isn't much of a problem--web browsers don't care that much about whitespace. Pickier clients, however, got thrown off and would complain about data being corrupt.

Wednesday, December 16, 2009

Cool Colors for Komodo Edit 5.2.4

The default font and color schemes for Komodo Edit were disgusting in my opinion.  So I made a scheme that looks like Zend/Eclipse or Mac Textmate.  I am using Windows 7 and this .ksf file goes into
C:\Users\Michael\AppData\Roaming\ActiveState\KomodoEdit\5.2\schemes
but for XP it’d probably be like
C:\Documents and Settings\Michael\Application Data\ActiveState\KomodoEdit\5.2\schemes
I installed these extensions and now it is my favorite code editor: ColorTab, JSTreeDrive, Mootools API Catalogs, SQLite Manager.
==============================
Version = 4
 
Booleans = {'caretLineVisible': True, 'preferFixed': 1, 'useSelFore': True}
 
CommonStyles = {'attribute name': {'fore': 7872391},
 'attribute value': {'fore': 3100463},
 'bracebad': {'back': 65535, 'bold': 1, 'fore': 6579400},
 'bracehighlight': {'back': 16758639, 'bold': 1, 'fore': 0},
 'classes': {'fore': 9145088},
 'comments': {'fore': 6908265, 'italic': False},
 'control characters': {'back': 16777215, 'fore': 0},
 'default_fixed': {'back': 16777215,
                   'bold': 0,
                   'eolfilled': 0,
                   'face': 'Consolas',
                   'fore': 0,
                   'hotspot': 0,
                   'italic': 0,
                   'size': 9,
                   'useFixed': 1},
 'default_proportional': {'back': 16777215,
                          'bold': 0,
                          'eolfilled': 0,
                          'face': 'Tahoma',
                          'fore': 0,
                          'hotspot': 0,
                          'italic': 0,
                          'size': 9,
                          'useFixed': 0},
 'fold markers': {'back': 16777215, 'fore': 5592405},
 'functions': {'fore': 9145088},
 'identifiers': {'fore': 0},
 'indent guides': {'fore': 8421504},
 'keywords': {'fore': 16711680},
 'keywords2': {'fore': 7872391},
 'linenumbers': {'back': None, 'fore': 5592405},
 'numbers': {'fore': 255},
 'operators': {'fore': 0},
 'preprocessor': {'fore': 6908265},
 'regex': {'fore': 25800},
 'stderr': {'fore': 16711680, 'italic': 1},
 'stdin': {'fore': 0},
 'stdout': {'fore': 0},
 'stringeol': {'back': 10079487, 'eolfilled': 1},
 'strings': {'fore': 39168},
 'tags': {'fore': 16724480},
 'variables': {'fore': 0}}
 
LanguageStyles = {'Apache': {'directives': {'fore': 9145088},
            'extensions': {'fore': 139},
            'ip_addresses': {'fore': 6908265},
            'parameters': {'fore': 7872391}},
 'C#': {'UUIDs': {'fore': 0},
        'commentdockeyword': {'fore': 0},
        'commentdockeyworderror': {'fore': 14483456},
        'globalclass': {'fore': 9145088},
        'verbatim': {'fore': 0}},
 'C++': {'UUIDs': {'fore': 0},
         'commentdockeyword': {'fore': 0},
         'commentdockeyworderror': {'fore': 14483456},
         'globalclass': {'fore': 9145088},
         'verbatim': {'fore': 0}},
 'CSS': {'compound_document_defaults': {'back': 13559807},
         'ids': {'fore': 139},
         'important': {'fore': 9109504},
         'tags': {'fore': 9145088},
         'values': {'fore': 7872391}},
 'Diff': {'additionline': {'fore': 9109504},
          'chunkheader': {'fore': 9145088},
          'deletionline': {'fore': 139},
          'diffline': {'fore': 6908265, 'italic': 1},
          'fileline': {'fore': 7872391, 'italic': 1}},
 'Django': {'compound_document_defaults': {'back': 14543103}},
 'Errors': {'Error lines': {'fore': 102, 'hotspot': 1, 'italic': 1}},
 'HTML': {'attributes': {'fore': 102},
          'cdata': {'fore': 9109504},
          'compound_document_defaults': {'back': 16772829}},
 'IDL': {'UUIDs': {'fore': 0},
         'commentdockeyword': {'fore': 0},
         'commentdockeyworderror': {'fore': 14483456},
         'globalclass': {'fore': 9145088},
         'verbatim': {'fore': 0}},
 'Java': {'UUIDs': {'fore': 0},
          'commentdockeyword': {'fore': 0},
          'commentdockeyworderror': {'fore': 14483456},
          'globalclass': {'fore': 9145088},
          'verbatim': {'fore': 0}},
 'JavaScript': {'UUIDs': {'fore': 0},
                'commentdockeyword': {'fore': 0},
                'commentdockeyworderror': {'fore': 14483456},
                'compound_document_defaults': {'back': 65535},
                'globalclass': {'fore': 9145088},
                'verbatim': {'fore': 0}},
 'Mason': {'compound_document_defaults': {'back': 14544639}},
 'PHP': {'identifiers': {'fore': 5308416},
         'keywords': {'fore': 16711680},
         'operators': {'fore': 0},
         'strings': {'fore': 39168},
         'tags': {'fore': 16711680},
         'variables': {'fore': 102}},
 'Perl': {'compound_document_defaults': {'back': 16050922},
          'here documents': {'bold': 1, 'fore': 8594211}},
 'Python': {'compound_document_defaults': {'back': 16777173},
            'decorators': {'fore': 39168}},
 'RHTML': {'compound_document_defaults': {'back': 10092543}},
 'Regex': {'charclass': {'fore': 2237106, 'italic': 1},
           'charescape': {'fore': 9145088, 'italic': 1},
           'charset_operator': {'fore': 7872391, 'size': 12},
           'comment': {'fore': 6908265, 'italic': 1},
           'default': {},
           'eol': {},
           'groupref': {'fore': 2237106, 'italic': 1},
           'grouptag': {'fore': 7872391, 'size': 8},
           'match_highlight': {'back': 10092543},
           'operator': {'fore': 7872391, 'size': 12},
           'quantifier': {'bold': 1, 'fore': 16711680, 'size': 12},
           'special': {'bold': 1, 'fore': 16711680},
           'text': {}},
 'Ruby': {'compound_document_defaults': {'back': 15525631}},
 'Rx': {'breakpoints': {'back': 14540253},
        'children': {'back': 14540236},
        'default': {'bold': 1},
        'parents': {'back': 13434828}},
 'Smarty': {'compound_document_defaults': {'back': 10092543}},
 'Text': {},
 'XML': {'cdata': {'fore': 9109504},
         'cdata content': {'fore': 9145088},
         'cdata tags': {'fore': 9109504},
         'data': {'fore': 2302862},
         'declarations': {'fore': 3358812},
         'entity references': {'fore': 2302862},
         'pi content': {'fore': 9145088},
         'pi tags': {'fore': 9109504},
         'prolog': {'fore': 0},
         'xpath attributes': {'fore': 9109504},
         'xpath content': {'fore': 36095},
         'xpath tags': {'fore': 11}},
 'reStructuredText': {'comment': {'fore': 9616695, 'italic': 1},
                      'identifier': {'fore': 1602765},
                      'operator': {'fore': 9109504},
                      'regex': {'bold': 1}}}
 
MiscLanguageSettings = {'Django': {'globalSubLanguageBackgroundEnabled': True},
 'HTML': {'globalSubLanguageBackgroundEnabled': False},
 'JavaScript': {'globalSubLanguageBackgroundEnabled': False},
 'Mason': {'globalSubLanguageBackgroundEnabled': True},
 'Perl': {'globalSubLanguageBackgroundEnabled': True},
 'Ruby': {'globalSubLanguageBackgroundEnabled': True}}
 
Colors = {'bookmarkColor': 14342664,
 'callingLineColor': 16764159,
 'caretFore': 0,
 'caretLineBack': 13434879,
 'currentLineColor': 16764108,
 'edgeColor': 15658734,
 'foldMarginColor': 16777215,
 'selBack': 16750899,
 'selFore': 16772846,
 'whitespaceColor': 0}
 
Indicators = {'find_highlighting': {'alpha': 100,
                       'color': 1110271,
                       'draw_underneath': True,
                       'style': 7},
 'linter_error': {'alpha': 100,
                  'color': 255,
                  'draw_underneath': True,
                  'style': 1},
 'linter_warning': {'alpha': 10,
                    'color': 10223515,
                    'draw_underneath': True,
                    'style': 1},
 'soft_characters': {'alpha': 100,
                     'color': 13209,
                     'draw_underneath': False,
                     'style': 6},
 'tabstop_current': {'alpha': 100,
                     'color': 3355647,
                     'draw_underneath': True,
                     'style': 7},
 'tabstop_pending': {'alpha': 100,
                     'color': 16751001,
                     'draw_underneath': True,
                     'style': 6},
 'tag_matching': {'alpha': 100,
                  'color': 33023,
                  'draw_underneath': True,
                  'style': 7}}

Thursday, October 8, 2009

Take Our Engineering Quiz!

It’s hiring time here at Fuery Solutions, and with the help of Craigslist, 10%+ unemployment, and a chipper ad, we have far too many applicants.
As such, we’re asking all of you job hunters to take a quick test.
1. Nuts and Bolts.


Build any single major UI piece in this screen shot wholly from JavaScript. You can use any framework you wish, but bonus points if you use either only core JS (impressive) or mootools (cuz we use it). You should fashion your own structured data (as if the labels and such were the result of an XHR).

It is perfectly fine to ignore graphical components, like the subtle gradients here and there. Do replace these with approximate solid colors.

In the interests of time, you can develop against a single browser platform. Do note if/where you took this shortcut. Also, you might want to stick with just a single box. It’s just a quickie.

2. Conceptual.

We currently store archived data via the “old-fashioned” way — apache over http on a web server. We want to move to a model where all static content (picture uploaded Word and Acrobat documents) are served directly through Amazon S3, where they are ultimately archived anyway.

Now, serving static content to the public from S3 is easy. The link above does just that! But here’s the clincher — we want to do it and control the access on a per user, per session basis. Keep in mind that these are end users — not technical people who have an AWS account and think of XML when you say the word “soap”. Actually, in a perfect world, we’d be able to control the flow of S3 object data directly through the authentication model we’re already using, which is based in Apache, PHP Sessions, and some other clever app-level logic for the rest (man in the middle attacks and such). How would you approach this problem? What sort of security worries does your solution address? Or not address? Is your solution efficient? Why or why not?

3. Product/UI Design.

One of the problems plaguing any database of contacts is the problem of duplicate contacts. Think about the products you use that have contacts as a data point — your phone, Gmail contacts, Outlook contacts, Facebook, Plaxo, and all the rest. Ponder the de-duplication experiences you’ve personally dealt with. Or, more likely, the experiences you’ve wished for when dealing with this problem yourself.

Within the context of a desktop based application (whether iTunes or Gmail), describe what the ideal user experience would entail and why. Draw a sketch or three and snap an shot with your phone if it helps.

Stuff to think about:
  • How much should a de-duping engine verify with you as the end-user?
  • How intelligent would the engine have to be to fulfill your ideal UI? What might the algorithm requirements (or even better, approach) be?
  • Do dead contacts go to heaven when they die? (What do you do with extra data? Or, at least, data that you’re not absolutely certain is duplicated?)

Thursday, May 14, 2009

Why doesn’t Mootools have a String.truncate() method?

I need a quick way to truncate strings! I’m surprised that neither MooTools’ String.js or String.Extras.js has such a method.  They have so many super-awesome functions, methods and extensions (I especially love the Date.js extensions!!).  Yeah, I really love mootools, and I feel compelled to share with the community.  So anyway, I wrote out a simple, straightforward String.truncate() function:

String.implement({
    /**
     * String.truncate(max, atChar, trail)
     *
     * ++All parameters are optional.
     * @param max = (integer) maximum length of truncated string. Defaults to 100 chars.
     * @param atChar = (string) truncate at the last index of this string. If not found, just truncates to max length.
     *                 If null, does not search and truncates to max length.
     * @param trail = (string) what you want appended to the end of the returned string
     *
     * @author Michael Fuery, Fuery Solutions, Inc. http://www.fuerysolutions.com/
     *
     * +Requires MooTools Core 1.2.2
     */
    truncate:function(max, atChar, trail){
        var s = this.trim();
        if(s.length&lt;1) return '';
        if(!$defined(max)) var max = 100;
        else max = max.toInt();
        if(!$defined(atChar)) var atChar=' '; // break at space
        else if(atChar == null) var atChar=false;
        if(!$defined(trail)) var trail = '...';
 
        if(s.length &gt; max) {
            var i=0;
            s = s.slice(0,max);
            if(atChar){
                if((i = s.lastIndexOf(atChar)) != -1){
                    s = s.substring(0, i);
                }else{
                    s = s.substring(0, max);
                }
            }
 
            s += trail;
        }
 
        return s;
    }
});

Tuesday, May 5, 2009

World Peace via Mootools

MerusCase disposes of A1Law and Tritek using Mootools.

While I was at it, I created a one line algorthm to solve world peace using our JS framework of choice, Mootools.  Yes, we love the moo over here at Fuery Solutions!



If you can't quite make out what that says, here's a recap:

MerusInit = function(){
  $$('A1Law','Tritek').each(function(e){
     e.dispose();
  }
}


World.Peace = $$('evil').each(function(e){e.destroy()});