Saturday, April 30, 2016

When no MAPHEAD is necessary

The first levelpack ever made for Keen 4 is distributed in just one file - it replaces GAMEMAPS only, not MAPHEAD. That's pretty impressive, because the author needed to align level data within the modified GAMEMAPS file correctly so that the default MAPHEAD data pointed to valid places.

I recently received an inquiry as to how to open such levels in Abiathar, since there was no file to specify as the map header.

To open those levels in any level editor, it's necessary to get the default MAPHEAD. Abiathar doesn't currently have a way to export the default one that it keeps inside itself, but once you acquire that file somewhere, it's able to deal with it like any other. I sent the inquirer a copy of the default that I had extracted from the game. Eventually I might add all the stored resources to the File Emitter.

Friday, April 29, 2016

You cannot put null bytes in clipboard text

Somebody was wondering whether the Windows clipboard can hold text that contains null characters (ASCII 0). The answer is no.

The clipboard is aware of the format of its contents; MSDN has a list of standard formats. The descriptions of all three formats that involve text each have this sentence:
A null character signals the end of the data.
There's no way to have null characters in the text because a null tells the string processing functions that they've reached the end of the string.

Thursday, April 28, 2016

You cannot pass arguments to functions with Rundll32

rundll32 is not a good choice if you need to invoke arbitrary Windows functions. The many reasons have discussed at length by Raymond Chen (1, 2, 3). Another pitfall that is not often mentioned is that there is no way to pass arguments to the function you call. Well, you can pass a single string if the function's signature matches what rundll32 expects. rundll32 will not parse out any numbers for you; in fact, it won't split the extra command line parts at all. All it does is pass a pointer to that string (LPSTR) at a certain point on the stack.

So, if you're trying to call a function that takes any set of arguments other than(HWND, HINSTNACE, LPSTR, int), you will, in effect, be passing random parameters. And by "random" I don't mean "something bizarrely different than what you intended" but "actually nondeterministic", as in the function very well might do completely different things from one run to the next.

If you need to call arbitrary functions from DLLs, consider using PowerShell to P/Invoke the API, or just write a real program to do it.

Wednesday, April 27, 2016

Running a program from the Internet on the command line

Attempting to use the Run dialog to start an EXE from the Internet usually results in your default browser opening and downloading the file, as opposed to it being downloaded by Windows and run.

Therefore, if you want to download and run an EXE, you'll need to do a little bit of scripting. PowerShell's Invoke-WebRequest is great for downloading things; WriteAllBytes can write the result to a file. Using those and some other little things, I composed this batch file that invokes PowerShell to accomplish the task.

@echo off
powershell -command $tmpPath = [System.IO.Path]::GetTempFileName() + '.exe'; 
 [System.IO.File]::WriteAllBytes($tmpPath, (Invoke-WebRequest "%*").Content);
 Start-Process $tmpPath

(The last three lines are actually one line, part of the arguments to powershell. Make sure you remove the line breaks.) The script finds a temporary file name (in the Temp directory), saves the EXE as it, and then runs it. The file isn't deleted after that, but since it's in Temp, it should get cleaned up eventually by disk cleanup tools. If you're not OK with that, you'll want to adjust the PowerShell part so that it waits for the executable to complete (use iex instead of Start-Process) and deletes it.

To use, save all that as a batch file and invoke it with a single parameter, the URL to execute.

Based on a Super User answer.

Tuesday, April 26, 2016

Program idea: Group Policy editor for Home editions

The thing that makes me most sad about the Home editions of Windows is the lack of several useful MMC snapins, mostly the Local Group Policy Editor. I discovered that Home editions do have some policy Registry entries, and I have heard that whacking gpedit.msc to run on Home editions does work. Of course, doing that is definitely a licensing violation.

Therefore, I'm considering writing a program that works like the Local Group Policy Editor, reading ADMX files and writing POL files. There are other parts of Group Policy that don't use the same places in the Registry (i.e. everything other than Administrative Templates), but those might come later, if I decide to do this at all.

Sunday, April 24, 2016

Changing Windows display fonts in Windows 8 and newer

The Window Color and Appearance dialog, which let you change the fonts and colors and other properties of various window elements, vanished in Windows 8. Fortunately, the Registry settings for those options haven't changed much; they're still located in:

HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics

The binary entries with names ending in "Font" are the ones that control the font of the various controls. IconFont, for instance, is responsible for almost all "content" text, including desktop icon captions.

The first four bytes are the font size in points, little endian and binary-NOT'ed. The font name starts at byte 0x1C, and is a null-terminated UTF16-LE string.

Custom IconFont setting (Comic Sans MS)
Changes take effect after a logoff/logon cycle.

The result, in Windows 10's Explorer
Based on my Super User answer.

Friday, April 22, 2016

%USERDOMAIN% for the SYSTEM account

You might expect that the environment variables %USERDOMAIN% and %USERNAME% for the SYSTEM account would hold values of NT AUTHORITY and SYSTEM, respectively. That's not the case. %USERNAME% when running as SYSTEM is always the computer name plus a dollar sign at the end. %USERDOMAIN% is the workgroup name (if the computer is not domain-joined) or NetBIOS domain name (if it does have a domain).

That makes sense on domains, since SYSTEM really does present the computer's credentials on the network, and the machine account username really is the computer name plus a dollar sign. I suppose the behavior on non-domain-joined machines is intended to match that.

If you want SYSTEM to see itself as NT AUTHORITY\SYSTEM, use the whoami utility.

Thursday, April 21, 2016

10K on Super User

Today I reached 10,000 reputation on Super User, becoming the 147th such user.

My usercard for Super User only

Wednesday, April 20, 2016

Renaming libraries on Windows 10

Windows 10 automatically adds "libraries" like Documents and Pictures to each user's Quick Access section of Explorer and also shows them under This PC. Interestingly, there is no Rename option on them.

Therefore, the only way to change the names of default libraries is to edit their desktop.ini file. The LocalizedResourceName entry usually refers to a localizable resource in a system DLL, but any value without a preceding @ sign will be treated as a literal value. So, you can do something like this:

LocalizedResourceName=Top of the Desk

After a logoff/logon cycle, the new name is shown:

Desktop and Documents renamed
I originally published this information in a Super User answer.

Tuesday, April 19, 2016

PowerShell script not running in MDT? Check your memory

Today I dealt with some unusual behavior with the Microsoft Deployment Toolkit. I had written a PowerShell script to poke at some things and print a few lines to the MDT log. Though I had added it to the task sequence in the right place, and ZTIPowershell said the script was started and that it exited with code 0, its text never got printed, but it had worked in a minimal task sequence.

When I tried to manually open a PowerShell prompt while running the main task sequence, it produced an out-of-memory error and then exited. Therefore, I'm almost certain that the problem stopping the script from actually running was that there wasn't enough RAM in the machine to handle the big task sequence and a PowerShell process. (There was only 900MB.)

Sunday, April 17, 2016

The Wake-on-LAN "magic packet" format

Wake-on-LAN is a feature that allows network cards to wake their computer from sleep upon receipt of a special packet. That packet can actually be in any format; network cards scan the entire payload for the special sequence so that they don't have to parse UDP or any other protocol.

A run of six FF bytes starts the magic sequence. It is then followed by sixteen instances of the card's six-byte MAC address.

Wikipedia says that the sequence is usually delivered over UDP or in a raw frame with EtherType 0x0842.

Saturday, April 16, 2016

When Bash on Ubuntu on Windows can't update because it "could not resolve" an Ubuntu server

An issue people are running into with Windows 10's new support for Ubuntu's Bash shell is that it sometimes has no Internet connectivity and therefore cannot update. Specifically, this text appears as part of the output of sudo apt-get update:

Could not resolve 'archive.ubuntu.com'

There are two likely causes mentioned in the discussion surrounding the issue on GitHub:

  1. /etc/resolv.conf didn't get generated correctly. Add a nameserver line with the address of a valid DNS server. That seems to work best when the DNS server is on the local network, i.e. is the router. For example, nameserver 8.8.8.8 sets Google DNS as a DNS resolver.
  2. An antivirus application is interfering with Bash's network connections. Try disabling the firewall.

Friday, April 15, 2016

Intel BIOS error 8110 or 8111

Today I was dealing with a server with an Intel BIOS that produced error 8111 when started. It continued to boot if a key was pressed, but a warning light came on. This Intel document lists the POST codes for their server motherboards. 8110 and 8111 mean that processor 1 or process 2 (respectively) reported an internal error, referred to as IERR. Apparently, that can also come from other devices, like memory.

I set the processor retesting option in the BIOS settings, rebooted, and the error went away. I conclude that my processors are not faulty; something else experienced a possibly-temporary problem.

Thursday, April 14, 2016

The correct format of the fSMORoleOwner field on the Infrastructure object

If you try to gracefully demote a domain controller from a domain where another DC has been forcibly removed, you may get an error saying that the machine was "unable to determine ownership of floating single-master operation roles". That happens when the forcibly-demoted DC was holding a FSMO role, even if that role was just the management of DomainDnsZones or ForestDnsZones, not one of the normal five.

The problem can be corrected by adjusting the fSMORoleOwner field on the Infrastructure object of the section with ADSI Edit. If you get the format wrong when you try to update the field, you'll receive an error telling you that the "role owner attribute could not be read". The correct format for the role owner field is this:

CN=NTDS Settings,CN=ServerName,CN=Servers,CN=SiteName,CN=Sites,CN=Configuration,DC=DomainName,DC=DomainTld

For example, this says that the new role owner in the default site of the example.com domain is a server called BIGBOX:

CN=NTDS Settings,CN=BIGBOX,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=example,DC=com

Wednesday, April 13, 2016

Translating a SID string to a NetBIOS-style username in PowerShell

Some functions (especially through WMI) return only SID strings, which are not very human-readable. Therefore, it may be helpful - or even necessary, depending on what you want to do with the string - to get the name of the principal the SID string represents.

The final section of this Microsoft blog-ish article shows how to do that, though it only mentions Active Directory accounts. The code also works for local accounts and the built-in ones like Administrators.

$sid = New-Object System.Security.Principal.SecurityIdentifier($sidString)
$user = $sid.Translate([System.Security.Principal.NTAccount])

You can then get the DOMAIN\user form of the account name with the $user.Value property.

Tuesday, April 12, 2016

You can only have Legacy Network Adapters in Generation 1 VMs

Today I was trying to follow some instructions on how to boot a Hyper-V virtual machine from the network, and the steps said to add a Legacy Network Adapter to the machine, but the only similar thing I could find in the list of add-able things was a normal Network Adapter.

It turns out I was on a Generation 2 VM, and only Generation 1 VMs can have the legacy style of network adapter. Though it looks like a G2's network adapter will work fine - the problem I was having originally was with the network boot server, not necessarily my configuration. (I got to the PXE searching screen, and it found the server, but the downloaded boot file was zero bytes.)

Monday, April 11, 2016

When Bamboo tablets start having input lag

Sometimes, after several hibernate cycles, my Bamboo tablet starts lagging severely; mouse movements from the pen take a while to register with the computer. Unplugging and replugging it into the USB port does not help. The only thing that helps is to reboot the computer.

Removing dust from the device with a damp wipe may help prevent problems with it, but it looks like once a tablet gets into this state, only a full reboot will fix it. Not hibernating for so long may also help, as it's never happened to me after only one or two cycles.

Sunday, April 10, 2016

Quickly testing dangerous things in VMs with Hyper-V's checkpoints

Microsoft's Hyper-V virtualization platform has a fantastic feature called checkpoints. At any time, you can choose Checkpoints from the Action menu to create a snapshot of the virtual machine's disk and state. (It doesn't make a full copy of the disk, it just starts journaling changes.) If you make a critical error in some procedure, you can right-click the checkpoint in the Checkpoints sector of the Hyper-V Manager and choose Revert. After a few seconds, the VM will be back exactly as it was when you made the checkpoint, other than needing to be unlocked (because you reconnected to your session).

Once you're done with the checkpoint, you can delete it from the Hyper-V Manager. After that's done, changes to the VHDs will no longer be journaled, and the space used for the other state is freed.

Saturday, April 9, 2016

Checking which users can run which procedures in SQL Anywhere

If you're interested in getting the security information on your SQL Anywhere stored procedures, you can use this little query:

select su.user_name, sp.proc_name from SYS.SYSPROCPERM sg
inner join SYS.SYSUSER su on su.user_id = sg.grantee 
inner join SYS.SYSPROCEDURE sp on sp.proc_id = sg.proc_id

You'll get a list of grants, with the grantee user's name and the name of the procedure on which execute permission has been granted.

If you're just interested in one user's permissions, use this:

select sp.proc_name from SYS.SYSPROCPERM sg
inner join SYS.SYSUSER su on su.user_id = sg.grantee 
inner join SYS.SYSPROCEDURE sp on sp.proc_id = sg.proc_id
where su.user_name = 'USERNAME'

You'll just get a list of procedures that the user can run.

(Tested on SQL Anywhere 11. May or may not work on other versions or similar products.)

Friday, April 8, 2016

SQL string concatenation + unchecked user input = SQL injection

SQL injection is a way for attackers to compromise your database by sending input that causes your query to run SQL code rather than just transferring data.

If you're developing a program that you think might be vulnerable to SQL injection, you can look for two things that together signal a vulnerability:

  1. String concatenation - the dynamic construction of SQL commands. The S stands for Structured, which means you shouldn't treat the commands as normal text; they have special structure. There may be a better way to accomplish what you're after without operating on text. For example, parameterization is a solid way to pass any data into a query safely.
  2. Unchecked, untrusted user input to the function that builds the SQL query. If you're sure that a procedure will only be called on trusted data (like from other procedures you create that don't take user input), it doesn't really matter whether your own application can do bad things to itself. Functions that do accept possibly-hostile input should either paramaterize queries or implement some really solid escaping (which is harder than you'd think).
If you only have stored procedures, a good key phrase to check for (at least on SQL Anywhere) is EXECUTE IMMEDIATE.

Thursday, April 7, 2016

Getting the Bash shell on Windows 10

With Insider build 14316, Windows 10 can include Ubuntu's Bash shell natively. The article explains how to enable the feature, and I summarize the relevant parts here:

  1. Update to build 14316 (requires an Insider account on the Fast ring)
  2. Enable Developer Mode (Settings → Update & security → For developers)
  3. Enable the Windows Subsystem for Linux (Beta) feature in the classic Windows Features dialog
  4. Type bash in a command prompt
  5. Answer the confirmation prompt affirmatively with a y
All necessary features will be unpacked and set up for you.

Wednesday, April 6, 2016

When permissions entries only show a View button, not Edit

Earlier today, I answered this Super User question, the poster of which was confused as to why some entries in the advanced security settings for Windows files changed the Edit button's label to View and couldn't be modified.

That happens when the entries are inherited from the parent object. Access control entries are evidently supposed to be modified on the object that originated them.

If you need to change or remove those entries, you can click the Disable inheritance button and choose to convert the inherited entries to explicit entries on the object.

The top option converts inherited entries
Once that's done, the View button will become Edit, and you'll be able to change the entry's settings.

Tuesday, April 5, 2016

Missing images on HTTPS? They have to be HTTPS too

A couple days ago, I noticed that Blogger allows HTTPS access to blogs, so I turned that on in a hurry. The HTTP version doesn't redirect automatically, but HTTPS started working, with the exception of the Lojban Stack Exchange site proposal ad on the right. The image was not appearing at all there.

The problem was that the image wasn't served over HTTPS. Most major browsers I'm aware of require secure pages to load only secure content - even if that content is just images. (Of course, unsecure pages can load secure content.) Updating the URL of the image to the HTTPS version fixed the problem.

Monday, April 4, 2016

Encryption doesn't help very much if everyone has the key

Let's say you want your app to communicate securely to its server. So you decide to encrypt the data. That's great! But how do you determine the key?

If you hardcode an encryption key into your client and server, you've given it to everybody, including bad guys who want to intercept your traffic. It doesn't matter how much you obfuscate it; the key will get found. Anybody who has the key can decrypt the traffic, and so encrypting your traffic doesn't help at all if you distribute that key freely.

If you have the server send the client the key to use each session, a bad guy listening on the network can grab the key too and use it to decrypt the data. Again, you're then just handing everyone the secret.

The right way to do encryption over an untrusted network with untrusted clients is with public-key infrastructure and key exchange. If you distribute your public key with the client, it can check whether the server is legit (i.e. not spoofed by an attacker). Have the client encrypt a random symmetric key with the public key, then the server will be able to unlock it with the private key, which only the server keeps. Once the symmetric key is securely transferred, you can open a normal session encrypted with it.

Sunday, April 3, 2016

Reversing the Sybase SQL Anywhere "SET HIDDEN" action

Yes, it's possible, and not very hard.

Sybase's SQL Anywhere product has a feature that allows the contents of functions, views, stored procedures, and triggers to be obfuscated in an allegedly one-way fashion. When an object is hidden with the SET HIDDEN clause, its contents are transformed into a mash of symbols. Even DBAs can't see the original text, and all the Sybase documentation says the plaintext is unrecoverable.

There is an undocumented feature in Sybase ASE that provides a command in diagnostic mode that can reverse the process. The problem is that SQL Anywhere does not have diagnostic mode or the dbcc command.

At first, I thought that the obfuscation process compiled the SQL into something lower-level, but no. The server program can reverse it, and does so when the object is called for.

Suppose you have a hidden procedure (or an encrypted stored procedure, as I've heard some call it) called SECRETPROC. To make the server load it into memory, you'll need to call it. Some installations of SQL Anywhere come with a tool labeled dbisql.exe that you can use as an interactive SQL environment. Invoke the procedure - it doesn't have to run; I would suggest calling it with a bogus number of arguments so that you don't accidentally run something bad. Then quickly open Task Manager, find the server process (called dbsrv11.exe for me because I'm using SQL Anywhere 11), right-click it, and choose Create dump file.

Once that finishes, open the resulting file in a hex editor (though Notepad might work too). I like XVI32 for such things. Search for the name of the procedure - e.g. SECRETPROC - with correct capitalization. There will be a few mentions of it (and the obfuscated version of it too), keep going until you see one that starts with create function and has a bunch of SQL code after it. Everything from that keyphrase to the next null byte is the stored procedures code.

If you're using XVI32, click on the beginning of the interesting part in the right pane and hold Shift while using the arrow keys to go to the end of the part you want. The text will turn red. You can then use Ctrl+C to copy the data, Ctrl+N to create a new file, Ctrl+V to paste the data, and File → Save to write it out to a new file.

I suppose SET HIDDEN isn't a security feature anymore.

Saturday, April 2, 2016

Using mountvol to assign drive letters that aren't letters

A few days ago, I noted that the subst command can create "drives" that are identified with any symbol, not just a letter. Of course, subst can only add alternate identifiers for already-lettered drives or folders. I thought that those symbols were just an illusion created by the command prompt.

It turns out that mountvol can assign any symbol to a volume, so you can legitimately have as many partition "letters" as you want. Also, programs that are not the command prompt can get into such drives. For instance, notepad -:\file.txt works perfectly fine from the Run dialog. (Of course, the Open dialog, which is essentially a mini Explorer, can't navigate in such directories, and won't even allow the direct typing in of a filename under such a drive - it thinks the name is not valid.)

Friday, April 1, 2016

When files appear in one program but not another

I just answered this Super User question. Its poster was baffled as to why a folder structure created in a certain program was accessible to that program but not even visible in Explorer.

There's a Windows feature in play, specifically file system redirection. It was invented in the XP to Vista transition, where many programs still assumed they were running as admin and so tried to write to system locations. The feature makes the programs think the writing succeeded, but Windows actually stores the data in %LOCALAPPDATA%\VirtualStore, a per-user location. When the unaware program comes looking for the files, Windows adds any entries from the virtual store to the directory listing.

Since Explorer and other Windows utilities (like the command prompt) are in the know, they won't see the virtual files. That can lead to much confusion. Windows Vista's Explorer had a button to go to the virtual store, but that Explorer feature seems to have been removed.