Link to home
Start Free TrialLog in
Avatar of Markus Fischer
Markus FischerFlag for Switzerland

asked on

For Experts: Obfuscated Access Contest

Hello experts,

As usual, this isn't a question as such, but rather a loose topic to generate a technical discussion about Access. All comments are welcome, but there is a challenge for the points. This time, I wanted something lighter, albeit not less technical.

Some of you might know (or remember) the "international obfuscated C code contest"; if not there is of course a Wikipedia page about it. I did incidentally learn a lot by studying some of the entries. This is similar on a much smaller scale. It's meant to be fun, although any sample or technique should actually work (so please test, review, and comment any full blown example). Simple ideas of possible obfuscation or anecdotes are also welcome. We might stumble upon a strange concept and develop a new original obfuscation together!

What do I mean by "obfuscation"? It's not simply poorly written or "shrouded" code, nor is it necessarily very complex. It can be something that looks as though it can't work but does; it can be a specially clever trick; it can be the blatant misuse of a feature to obtain a totally different effect; it can be using a bug as feature for some side effect; it can be anything, really... We will see.

Access being made of three distinct elements (the platform, Jet, and VB), there is potential for unexpected interactions. We routinely write SQL from VB; can we also write VB from a query? Forms and reports interact naturally with both; is there some unexpected way to use a control? VB code itself can certainly surprise us as well (not only by misusing line continuations and colons). Some queries definitely look entirely wrong... but return _something_. I must confess that in some previous threads in the series, especially the last one, I was sometimes thinking already about possible obfuscation.

One-liners, like "? CurrentDb!Table1.OpenRecordset()(1)", could be in a category of their own. Another would be for the most absurd usage of less known VB keywords, like "Imp" (my favourite). But the best is perhaps something that doesn't fit in any category...

Cheers!

Markus
(°v°)
Function Bye(): & "Cheers!": End Function
Private Sub &(°v°): MsgBox (°v°): End Sub

Open in new window

Avatar of Markus Fischer
Markus Fischer
Flag of Switzerland image

ASKER

I should have known. The '&' in the clever code was not and ampersand, but a one-character ellipse (...). Looks much better and it makes the sample work. I should have use the en-dash (but perhaps it gets eaten by the EE bug as well, lets see:)

If EE adds its own layer (and brand) of obfuscation, we are in for some confusing corrective comments for every piece of code...

(°v°)
ASKER CERTIFIED SOLUTION
Avatar of nico5038
nico5038
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Nico: I do love "Easter Eggs" and tend to add some to my own applications. Sadly, they have come out of fashion.

Jaffer: Thanks!

Rick: I guess it's only natural that the non-breaking space should be mentioned from the start in this thread. It's a fantastic obfuscating trick for naming tables, fields, modules, functions... I'm sure somebody will provide some creative VB code using them!

Speaking of cross-tabs and the naming of columns, try to use a column header that evaluates to an equal sign or to a string starting with an equal sign. Simply add a couple of entries into your field 'ColHeader' (or 'CatDesc'?) with an equal sign and open your cross-tab.

You will have a column '=', but that column will be empty. This is clearly a bug, and you can use the workaround PIVOT Col In(Null,'a','=') to fill the column correctly. But in order to turn this into a true "obfuscated query contest entry", one should do something useful (or funny) with it, else it's only that: a bug...

(°v°)
OK, I think I get the idea of what you're looking for.  How about this.

A function to return all the items selected in a list box, delimited by the character of your choice and encapsulated with a string of your choice too.

All done in a 1 line recursive function.

All code within is contained within the code snippet below.
Function ListBoxIn(lst As Object, lngCol As Long, strDelim1 As String, strDelim2 As String, lngItem As Long): On Error Resume Next:  ListBoxIn = ListBoxIn(lst, lngCol, strDelim1, strDelim2, (lngItem - 1)) & ListBoxIn & IIf(lngItem - 1, strDelim1, "") & strDelim2 & lst.Column(lngCol, lst.ItemsSelected(lngItem - 1)) & strDelim2: End Function

Open in new window

Obfuscated-ListBoxItems.mdb
ListBoxItems.PNG
Yes!

I was about to post that this thread didn't have any success, and whether I should try to rekindle it...

Your code is great; using the error to end recursion on a single expression and parsing bottom up is brilliant! I couldn't resist but add another trivial layer of obfuscation in the variable names (and adding a reference on your handle), I hope you don't mind me posting it.

Thanks, this is fun!
(°v°)
Function ListBoxIn(R, i, c, k, ²): On Error Resume Next: ListBoxIn = ListBoxIn(R, i, c, k, (² - 1)) & IIf(² - 1, c, "") & k & R.Column(i, R.ItemsSelected(² - 1)) & k: End Function

Open in new window

Don't mind you reposting it all. Ever since you posted and clarified what was meant by Obfuscation I went back to look up the commentary from Wikipedia.  Having clarified the objective the next task was dreaming something up to fit the bill but I also thought it might be nice to have something that someone could deem particularly useful as well.  Very common task to see people writing code to capture all the items selected in a list box and so often it is done with so many lines of code.  

Very cute how you captured my name in the variables as well, (I'm flattered).

In any case, perhaps now you won't have to consider your invitation for obfuscation to have been a failure. :)
SOLUTION
Avatar of DatabaseMX (Joe Anderson - Former Microsoft Access MVP)
DatabaseMX (Joe Anderson - Former Microsoft Access MVP)
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks MX' I'd love to have any insight anyone can offer regarding my other post....

https://www.experts-exchange.com/questions/23592547/Passing-a-Control-to-a-Function-from-a-JET-Query.html?anchorAnswerId=22084982#a22084982 and MX has been very determined to find the answere all day but so far no luck (anyone else want to take bite?

Meanwhile, back to Obsfucation, this one is sort of an extension of my previous idea.  Imagine for a moment that you have a query and you'd like to get a UNIQUE  list of the vales from that query, package it in a string on individual rows or perhaps a comma delimited list (or other ways - you decide), but then hey, why even bother with ADO or DAO, multi line functions and the like when you can do ith with a 1 line function.

Sample app also attached.

Ps.  The 5th parameter give you the option of extracting other columns of data besides just column 0.  Have fun. :)
Function RickCDL(R, i, c, k, ©): On Error Resume Next: RickCDL = Choose(R.RecordCount, c & k & R.Fields(©).Value & k & RickCDL(CurrentDb.OpenRecordset(i & " WHERE " & R.Fields(0).Name & " > " & R.Fields(©).Value, 4), i, c, k, ©)): End Function
 
Sub Sample()
    MsgBox Mid(RickCDL(CurrentDb.OpenRecordset("SELECT tblX10.X10 FROM tblX10", 4), "SELECT tblX10.X10 FROM tblX10", ",", "'", 0), 2)
    MsgBox Mid(RickCDL(CurrentDb.OpenRecordset("SELECT tblX10.X10 FROM tblX10", 4), "SELECT tblX10.X10 FROM tblX10", vbCrLf, "", 0), 2)
End Sub

Open in new window

Obfuscated-DAOorNot-.mdb
Bitwise operators.  Once upon a time I used to create constants to designate values for what Bit0 would be, bit1, bit2, bit3.... bit 22, bit23 and so on.  Sure be nice to have an array that had all those values on top, oh wait... how about a function that looks like an array and serves the same purpose except we need not provide it with the starting values...


Function Bit(i): Bit = 2 ^ i: End Function
 
Sub Sample()
    Dim lng As Long
    For lng = 0 To 63
        Debug.Print "Bit" & lng & ":"; vbTab & Bit(lng)
    Next lng
End Sub

Open in new window

LOL. I love the recursive opening of recordsets! Sure, to get a list of a dozen numbers in a string, why not stack up a dozen database objects and a dozen recordsets! This is grand. Thanks anew!

(^v^)
At the end of the day it's really a technique more than any one specific solution.  It can be spun so many different ways.  Compile a list of tables, Queries, Forms, Reports well just about anything and all from these single line functions.  Take then next step I'm not sure why we couldn't start stacking collections which gets really wild since collections can afteral hold just about anything, forms, reports, class objects, and more.  Could create for some very funky syntax effectively reshaping the way we write VBA.

Gives rise to things like this...

A function that populates multiple list boxes via a call back function based on class objects instantiated for that specific list box, an object that gets stuffed inside a collection, called into use by index and in this case to execute one of the many methods belonging to the class object itself.  What really unwinds the developers who come after me is the fact that the form and much of the application is code less, (Yea for the WithEvents operator).




Function FillList(ctl As Access.Control, varID As Variant, lngRow As Long, lngCol As Long, intCode As Integer): On Error Resume Next: FillList = gColObj.Item(CStr(ctl.Parent.hwnd & "FindIt" & atBreak & ctl.Name)).FillList(ctl, varID, lngRow, lngCol, intCode): End Function

Open in new window

harfang,

It's a shame we're not getting more participation on this thread.  I'd love to see what cleaver ideas others are willing to share.
Noticed a bug in a previous post.  Updated here.
Function RickCDL(R, i, c, k, ©): On Error Resume Next: RickCDL = Choose(R.RecordCount, c & k & R.Fields(©).Value & k & RickCDL(CurrentDb.OpenRecordset(i & " WHERE " & R.Fields(©).Name & " > " & R.Fields(©).Value, 4), i, c, k, ©)): End Function
 
Sub Sample()
    MsgBox Mid(RickCDL(CurrentDb.OpenRecordset("SELECT tblX10.X10 FROM tblX10", 4), "SELECT tblX10.X10 FROM tblX10", ",", "'", 0), 2)
    MsgBox Mid(RickCDL(CurrentDb.OpenRecordset("SELECT tblX10.X10 FROM tblX10", 4), "SELECT tblX10.X10 FROM tblX10", vbCrLf, "", 0), 2)
End Sub

Open in new window

Hello everybody!

As you might have noticed, I was off-line for a couple of months. At first, I stored the EE messages religiously, thinking I'd get around to them soon, then I stopped reading my mail altogether, and it piled up silently.

I finally cleaned the mess.

Among almost 1000 messages, 99.5% spam (2/3 in Cyrillic, it seems to be the current trend), I found quite a few "you have open questions" reminders. So I have: this one. I'm sure some CV volunteer tied her hands in order *not* to close it forcefully, and I find that touching. In case nobody cared one way or another, don't tell me! (^v°)

Of course, I could have simply closed this, but I had somewhere a piece totally obfuscated code, and I kept thinking I should dig for it, clean it up, and post it here, just for the fun. I also had ideas for the next thread, or possibly an article (what's the status about those, btw?).

Anyway, this was the idea: a simple "about" box, where my name was not to appear. At all. Predictably, I hid an easter egg in that form, so that three names could be made to appear. It was for an old version, and the animation is a bit too fast, but it's still cute. It featured two logos (replaced by labels), the name and version of the application, and some technical details (all omitted). There is really just this one button. What can you do with a button?

Care to look for it?

The attachment is the full form as text, load it to an empty database if you want to try, and I copy just the module in the code window for fun. Beware, though, the original is more reliable... every detail counts.

It's of course intentionally unreadable. As added challenge, I decided to write each sub as a single line, but with line continuation characters before the maximal self-imposed 80-character page width. The line continuation characters are limited, so in effect, there was an upper boundary, at least per function.

The silly thing with one-liners is that you can no longer use any If constructs. But this is rather good, because it's much more fun to hide the logic, and If/Then/Else is much too obvious.

Have fun, it's good to be back.
(°v°)

'
' Form Module   Form_fdlgAbout
' Copyright     Public domain
' Author        Markus G Fischer
' Created       Feb-1998
' Updated       once for each version
'
'
' A little Easter Egg :)
'
Option Explicit: Private  
 
Public Function Case (of, Optional "):        For " = 1 To Len(of): Mid(of, _
", 1) = Chr(-(&HFF Imp Asc(Mid(of, "))) - 1): Next: Case  = of: End Function
 
Private Sub Form_KeyUp(k As Integer, s As Integer): Static c As Byte: On Error _
Resume Next: Select Case s: Case 0:  .Visible =  .Visible - (k = 32): c = 0: _
Case 6: Select Case k: Case 70: c = 9 * -(c = 2): Case 74: c = 5 * -(c = 4): _
Tag = Tag & Case ("µ"): Case 71: c = 2 * -(c = 1): Case 79: c = 9 * -(c = _
5): Case 68: c = 4: Tag = Case ("»~aß"): Case 66: c = 5 * -(c = 4): Tag = _
Tag & Case ("½Üa~`:"): Case 77: c = 1: Tag = Case ("²~`R߸Ñß¹RSa"): _
Case Else: c = 9 * -(c = 9): End Select: TimerInterval = -(c = 9): Case Else: _
c = 0: End Select: End Sub
 
Private Sub Form_Timer(): Const X = 0.017453292: Static i As Byte, A As Long, _
B As Long, c As Long, D As Long, E As Long, Y: On Error Resume Next: With _
cmdOK: Select Case i: Case 0: Set   = Me(8): Set Y = Me(2): Y.Tag = Y.Caption _
: B = .Width: i = 1: Case 1: A = A + 10: .Width = B + 300 * Sin(A * X): i = _
IIf(A < 180, i, 2): Case 2: .Default = 0: i = 3: RunCommand 50: Case 3: A = 90 _
: B = .Top: c = .Left: D = 1530: E = 1350: i = 4: Case 4: A = A + 10: .Top = D _
+ E * Sin(A * X): .Left = c + E * Cos(A * X): i = IIf( .Visible And A >= 325, _
5, IIf(A < 450, i, 6)): Case 5: Y.Caption = Tag:  .Visible = False: i = 4: _
Case 6: .Top = B: .Left = c: i = 3: A = 0: D = 300: i = 7: Case 7: B = .Width: _
c = .Left: .Default = B:  .Visible = c: i = 8: Case 8: A = A + 10: .Width = B _
+ D * Sin(A * X): .Left = B + c - .Width: i = IIf(A < 180, i, 9): Case 9: i = _
108: TimerInterval = 1000: Case Else: TimerInterval = 0: i = 0: A = 0: Y _
.Caption = Y.Tag: End Select: End With: Repaint: DoEvents: End Sub
 
Private Sub cmdOK_Click(): DoCmd.Close acForm, Me.Name: End Sub
 
'
'                                                                            ok?
'

Open in new window

about.txt
It's as I feared. The character bug is still active and hungry. I did use some non-conventional characters, and they became bug fodder. Some blanks are intentional, though. Better to read the module in the attachment...

(°v°)
Hi Markus and welcome back :)

>I did use some non-conventional characters, and they became bug fodder
This is why I only place English text in VBA, other non-English/non-conventional characters are PC dependent, thus turns garbage on some other PCs :(

jaffer
Wow. I did receive the "you have open questions" mails, but still! How long has this been open?

Time to close this. I don't think I will restart my "expert questions" thread after such a long break, but who knows?

I'm currently experimenting with articles instead, these two should be published in a couple of days:

http:/articles/Microsoft/Development/MS_Access/Access-Tips-Tricks-The-Smart-Combo.html

http:/articles/Software/Office_Productivity/Office_Suites/MS_Office/Excel/Excel-Tips-Tricks-The-Camera-Tool.html

Does this mean I'm back on EE? We'll see. I did miss you all, though.

Cheers!
(°v°)
Thanks for participating, and thanks for your patience -- (^v°)