Monday, December 2, 2013

Moving windows OS between disks...

Mnimalistic version:
If acronis cloning utility messed your drive - don't use that tool and create partitions by hand. Also migrate data manually (and using scripts provided).

Part 1: Problems with disk cloning...

Long story

Recently I've bought a new HDD (SDD in fact).
I wanted to use Acronis disk cloning utility (included in my box version of kingston drive) and... it encountered some problems.
First of all - I was able to migrate the data.
Afterwards I've exchanged the drives. Since then my AHCI controller failed to detect drives.
Next step was... to connect the drive using USB-enclosure and wipe out all the partitions info.
Then it started up. But I had to clone my drive. Again - acronis. It failed with a message "Cannot write the data to the sector 0". Hardware failure?
Again connected as USB - it works fine and I can write to it. Maybe it's some security issue? BIOS shows no restrictions, I have no hardware password on the drive...
I'm creating partitions by hand (without acronis). It worked.

Summary

Conclusion: Acronis messed the disk structure in some way.
Solution: Create partition by hand and do NOT use acronis tool.

Part 2: Manual data migration

Long story

Now I need to migrate the files... but you cannot do it from another Windows copy as the users from another OS instance are not present in this OS. Windows ACL sux a bit.
I can take the ownership of files but then my OS would be different than original.
I could re-install the OS and it sounds like a good plan... but I'm going to try something else.
Microsoft made its own command line shell. Since windows is not enough for "real tasks" they tried to create something like is known on Unix systems. But they wanted to make it better. The results are rather poor.
PowerShell is an interface to deal with C#/.NET/whatever system objects. It has its own commands with dumb names. It works with pipe, objects and strings, strange iterators and conversions.
So I started powershell and made a script to modify the permissions. Due to mIcrosoft design I had to store current object's owner, set myself as the new owner, add access rule for myself to the object, restore the owner. It worked until some point.
My script is running from administrator console. I had to lower system restrictions to run the .ps1 scripts.
Next problem: I cannot change the owner if the directory has no permission for me to modify it (ex. object without any permissions). I need to escalate my privileges for that. I can do it using PSCX... but it doesn't work for some reason (and installation is not that obvious).
Right now I'm waiting for my OS to restart (then I would be done with the installation of .NET 4.5 and wIndows instrumantation management or whatever). Without it I don't have powershell 3.
Will it work after reboot? With wIndows you never know and every action such as mouse click or second to pass - every such action required a restart. Well... maybe not every but many. Too many. And this is a hybrid OD which is meant to be modular, plugable and secure. Instead it is not secure (you cannot escalate your privileges easily but malware can), nor plugable (it's just fat and overloaded having many libs and crappy resources without owner), nor modular (there are no such things as modules... assemblies maybe... and files...). And in the new version... it's a spyware too.
Well... I guess that my software development might end when my MSDN license would expire. But we'll see.
Steam - I hope that you can move the gaming world into tux.

List of the problems I have encountered when fighting with NTFS stinky permissions:
  1. I need to run as privileged user. Sometime Administrator is not enough. So I neet to exploit system and gain access to NT AUTHORITY\SYSTEM.
  2. Some objects could be owned by TrustedInstaller and no one else would have access to them. As SYSTEM I can take over the ownership... but I cannot see current owner. If I take the ownership - I would loose the owner information. In other words - I could not restore ownership of such objects as I don't know who owns them.

I think that developers from Microsoft made some assumptions...

Most users are extremely dumb. We should not allow them to modify the system.
Most developers are not to be trusted (I agree with that one) and we should limit their access to the system.  However developers are not that dumb and we should give them more access than computer owner (user) has (I don't agree with that one).
Developers from Microsoft are the best and they never make mistakes (I strongly disagree). Windows system is perfect and cannot be hacked. It is closed source so no one can hack it. 
Windows system is bug free.
To support the above:
User cannot modify system files. 
User cannot modify system registry. 
User has no access to system account. 
There is no documentation for the system inner logic. 
The are system methods to access some system things but no interface was ever planned. 
New releases and patches are adding more constraints instead of new interfaces. 
The are plenty viruses that gain system credentials writing themselves into system areas which are not accessible fire normal users. 
They still have their sources closed.

Access details

After some time I was able to create some script. Its logic:

  1. ForEach FileSystem element on drive: call f_grant()
    1. Add FullControl security rule to the element
      1. On AccessDenied error take ownership of the item and try again
    2. Iterate over elements children (directories and files inside other directories)
      1. Call f_grant()
  2. ForEach top FileSystem element on drive:
    1. Move it to the destination drive
  3. ForEach FileSystem element on drive: call f_revoke
    1. Iterate over elements children (directories and files inside other directories)
      1. Call f_revoke()
    2. Revoke FullControl security rule from the element
  4. Accept that owner of some elements (usually TrustedInstaller and viruses) would be lost

Problems I've encountered

MSDN site won't work correctly on HTML web browser.
MSDN site is not a valid HTML document.
MSDN site won't work correctly on InternetExplorer application in some versions.
MSDN site is slow on InternetExplorer application (at least in IE10).
MSDN says that I need to get current ACL in order to restore it later. I cannot do that if I have no privileges to do it. I need to take ownership of the object to do it. If I take the ownership I would loose information about the previous owner (which I was not able to retrieve as I had no access). This is a dead end.

Summary

Conclusion: Manual migration is challenging
Solution: Use scripts provided

# I'm not sure if this is really needed... I'm running the script as system (who is above administrator)
# First of all - set access to the root filesystem as it is inherited by its children
# After permissions change use mv command from powershell in privileged session (run from administrator or system)

# Uncomment those lines if needed... you might need to install PSCX then
#Import-Module "PSCX"
#Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeRestorePrivilege", $true) #Necessary to set Owner Permissions
#Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeBackupPrivilege", $true) #Necessary to bypass Traverse Checking
#Set-Privilege (new-object Pscx.Interop.TokenPrivilege "SeTakeOwnershipPrivilege", $true) #Necessary to override FilePermissions & take Ownership

# Get WindowsIdentity of current user
[System.Security.Principal.IdentityReference]$currentUser=([System.Security.Principal.WindowsIdentity]::GetCurrent()).owner
$accRule=new-object System.Security.AccessControl.FileSystemAccessRule($currentUser, 'FullControl','Allow')

$currentHostname=$env:COMPUTERNAME

function f($o){
$fn=$o.fullname
try{
$AC=$o.GetAccessControl()
$oldOwnerName=$oldAC.owner
} catch [System.UnauthorizedAccessException] {
Write-Host $o.fullname 'access denied - need to change owner (previous value will be lost)'
takeown /F $o.fullname /S \\$currentHostname 2>$null 1>$null
$AC=$o.GetAccessControl()
$oldOwnerName=$oldAC.owner
}
$AC.SetAccessRule($accRule)
set-acl -aclObject $AC -path $o.fullname 2>$null
if(!$?){ # try-catch won't work
# Write-Host $o.fullname 'access denied - need to change owner (previous value will be lost)'
takeown /F $o.fullname /S \\$currentHostname 2>$null 1>$null
set-acl -aclObject $AC -path $o.fullname
}
if       ($_ -is [IO.FileInfo]) {
Write-Host ($o.name).padright(32,'.') $oldOwnerName
} elseif ($_ -is [IO.DirectoryInfo]) {
$o.fullname
(Get-ChildItem $o.fullname)|foreach{f($_)}
} else {
}
}
gci "N:\windows" |foreach{f($_)}