Packing code within code – a HTA exercise in string manipulation
I was working on a HTA tool this week, and to make things easier I wanted to encapsulate another HTA within it – really I just didn’t want to have to send two files to the user, I wanted everything in one, and rather than take the obvious approach of putting them both into a self-extracting zip, I decided to work out how to include the code of File B in File A.
Note – you can find the test files for this article on my companion site, CTOGoneWild
Pretty easy stuff I thought, just split B up into a string, and include a simple routine to write it out to the temp directory
1 : Dim s : s="Some text to output to a file" &_ 2 : " which is more than one line and go" &_ 4 : "es on a bit." 6 : Dim fso: Set fso = CreateObject("Scripting.filesystemobject") 8 : fso.createtextfile("test.txt").write s
Well, that was easy I thought, so I wrote a simple script to take my existing HTA file and output it as a series of strings, and that’s where things got complicated. Firstly, pesky new line chars messed up the formatting of my text, then there was the whole line length problem, tabs didnt transfer nicely, and to top it all, you can’t use “” in a string within a HTA – the IE interface interprets that as the end of your real script (it does not notice it’s within a script) so that’s not nice either.
You can see what I mean using this test shell – it should nicely encapsulate itself, but you’ll see it screws up bigtime.
4 : APPLICATIONNAME="My HTML application" 6 : ID="MyHTMLapplication" 7 : VERSION="1.0"/> 8 : </head> 9 : <script language="VBScript"> 10 : Option explicit 11 : Sub Window_OnLoad 12 : Dim a : a = "Some random text in the code just to make things more interesting." 13 : Dim fso : Set fso = CreateObject("scripting.filesystemobject") 14 : Dim s : s = fso.OpenTextFile("test.hta").ReadAll 15 : Dim i,strTemp 16 : For i = 1 To Len(s) Step 50 17 : strTemp = strTemp & """" & Mid(s,i,50) & """ &_" & vbcrlf 18 : Next 19 : details.value = strTemp 20 : End Sub 21 : 22 : bgcolor="white"> 23 : <textarea id="details" style="width:100%;height:100%"></textarea> 24 : </body> 25 : </html>
So, what’s the secret? Well simply it’s to do some sneaky char substitution prior to outputting the data to make it “safe”. Things like quotation marks, the tag “</script”>, line feeds and tabs must all be removed, and then inserted back in later. By doing this you can end up with some nice output like:
"<html>|n<head>|n<title>My HTML application</title>" &_ "|n<HTA:APPLICATION|n APPLICATIONNAME=|qMy HTML ap" &_ "plication|q|n ID=|qMyHTMLapplication|q|n VERSION" &_ "=|q1.0|q/>|n</head>|n<script language=|qVBScript|q" &_ ">|nOption explicit|nSub Window_OnLoad|n|tDim a : a" &_ " = |qSome random text in the code just to make thi" &_ "ngs more interesting.|q|n|tDim fso : Set fso = Cre" &_ "ateObject(|qscripting.filesystemobject|q)|n|tDim s" &_ " : s = fso.OpenTextFile(|qtest2.hta|q).ReadAll|n|t" &_ "Dim i,strTemp |n|ts=Replace(s,Chr(34),|q||q & |qq|" &_ "q) : s = Replace(s,vbCrLf,|q||q & |qn|q) : s = Re" &_ "place(s,vbTab,|q||q & |qt|q)|n|ts=Replace(s,|q<|q " &_ "& |q/script>|q,|q||q & |qs|q)|n|tFor i = 1 To Len(" &_ "s) Step 50|n|t|tstrTemp = strTemp & |q|q|q|q & Mid" &_ "(s,i,50) & |q|q|q &_|q & vbcrlf|n|tNext|n|tdetails" &_ ".value = strTemp |nEnd Sub|n|s|n<body bgcolor=|qw" &_ "hite|q>|n<textarea id=|qdetails|q style=|qwidth:10" &_ "0%;height:100%|q></textarea>|n</body>|n</html>"
Simply add this line after line 15 of the script above to make the substitutions:
s=Replace(s,Chr(34),"|" & "q") : s = Replace(s,vbCrLf,"|" & "n") s = Replace(s,vbTab,"|" & "t"): s=Replace(s,"<" & "/script>","|" & "s")
Of course, when you dump your script out again, you need to make the reverse changes PRIOR to the output. Why do I do something as odd as break the replacement lines up like “|” & “n” instead of just using “|n”? Well, of course it’s so I can pack myself – if I use “|n” directly the unpacker will incorrectly unpack the code itself – try it, it took me a while to work it out myself.
So, the final solution wrapped up with unpack code looks like this. I skipped the string off the top, you can copy that in from above.
1 : Dim s : s = "<html>|n<head>|n<title>My HTML application</title>" &_ ... 18 : "0%;height:100%|q></textarea>|n</body>|n</html>" 19 : Dim fso : Set fso = CreateObject("scripting.filesystemobject") 20 : Dim myfile : Set myfile = fso.createtextfile("output.txt",2,True) 21 : s=Replace(s,"|q",Chr(34)) : s = Replace(s,"|n",vbCrLf) : s = Replace(s,"|t",vbTab):s=Replace(s,"|s","<" & "/script>") 22 : myfile.write s
The next step is of course to add some compression here – but, that’s a story for another day.
Comments