How to find the logical ordering of a page
The row offset array in an index leaf node page determines the logical order of rows within the page, which may differ from the physical order. Below is a demo script that uses the undocumented DBCC IND. Run only on  a test system.

USE tempdb;

SET NOCOUNT ON;

IF OBJECT_ID(N'dbo.ClusteredIndexExample', 'U') IS NOT NULL
BEGIN
    DROP TABLE dbo.ClusteredIndexExample;
END

CREATE TABLE dbo.ClusteredIndexExample(
     KeyData varchar(10) NOT NULL 
        CONSTRAINT PK_ClusteredIndexExample PRIMARY KEY CLUSTERED
    ,OtherData varchar(1000) NOT NULL       
    ); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 1', REPLICATE('1', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 3', REPLICATE('3', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 4', REPLICATE('4', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 2', REPLICATE('2', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 5', REPLICATE('5', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 6', REPLICATE('6', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 7', REPLICATE('7', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 8', REPLICATE('8', 1000)); 
INSERT INTO dbo.ClusteredIndexExample VALUES ('Row 9', REPLICATE('9', 1000)); 

IF OBJECT_ID(N'tempdb..#dbcc_results', 'U') IS NOT NULL
BEGIN
    DROP TABLE #dbcc_results;
END 

CREATE TABLE #dbcc_results(
     PageFID    int
    ,PagePID int
    ,IAMFID int
    ,IAMPID int
    ,ObjectID int
    ,IndexID int
    ,PartitionNumber int
    ,PartitionID bigint
    ,iam_chain_type varchar(20)
    ,PageType int
    ,IndexLevel int
    ,NextPageFID int
    ,NextPagePID int
    ,PrevPageFID int
    ,PrevPagePID int
    );

DECLARE 
     @DBID int
    ,@ObjectID int
    ,@PagePID int
    ,@PageFID int;

SELECT
     @DBID = DB_ID()
    ,@ObjectID = OBJECT_ID(N'dbo.ClusteredIndexExample');

INSERT INTO #dbcc_results
    EXEC sp_executesql N'DBCC IND(@DBID, @ObjectID, 1, 1) WITH NO_INFOMSGS;'
        ,N'@DBID int, @ObjectID int'
        ,@DBID
        ,@ObjectID = @ObjectID;

--return DBCC results to client
DBCC TRACEON(3604) WITH NO_INFOMSGS; 

--get data pages for this table, following forward pointers in logical order
DECLARE data_pages CURSOR LOCAL FAST_FORWARD FOR
WITH data_pages AS (
    SELECT
         PageFID
        ,PagePID
        ,0 AS PageSequence
    FROM #dbcc_results
    WHERE 
        PageType = 1 --data page
        AND PrevPageFID = 0
    UNION ALL
    SELECT
         #dbcc_results.PageFID
        ,#dbcc_results.PagePID
        ,data_pages.PageSequence + 1 AS PageSequence
    FROM #dbcc_results
    JOIN data_pages ON
        data_pages.PageFID = #dbcc_results.PrevPageFID
        AND data_pages.PagePID = #dbcc_results.PrevPagePID
    )
SELECT 
     PageFID
    ,PagePID
FROM data_pages;

OPEN data_pages;
WHILE 1 = 1
BEGIN
    FETCH NEXT FROM data_pages INTO @PageFID, @PagePID;
    IF @@FETCH_STATUS = -1 BREAK;

    --dump page: NOTE physical order within page may be different than logical order
    DBCC PAGE(@DBID, @PageFID, @PagePID, 2) WITH NO_INFOMSGS; 

END
CLOSE data_pages;
DEALLOCATE data_pages;

--don't return DBCC results to client any more
DBCC TRACEOFF(3604) WITH NO_INFOMSGS;

--cleanup
DROP TABLE dbo.ClusteredIndexExample, #dbcc_results; 
GO